Compare commits

...

26 Commits

Author SHA1 Message Date
4e7fa44301 Add delay for writing files 2021-03-23 18:27:05 -06:00
Elijah Lucian
104d39b4c6 🐛🔨 2021-03-24 00:04:04 -07:00
Elijah Lucian
88e62bdf48 Merge branch 'master' of https://git.tannercollin.com/tanner/3Dshock 2021-03-23 23:40:56 -07:00
Elijah Lucian
b9c8b6c1e6 💎 2021-03-23 23:40:53 -07:00
66f86827ff Allow adjusting LED time and add time info 2021-03-23 17:30:47 -06:00
Elijah Lucian
8ca4d55045 🔧 2021-03-17 10:33:11 -06:00
E
2b495779d3 adding dank transition 2021-03-11 13:11:18 -07:00
Tanner
ce46f006d5 Add random delay to fake download 2021-03-10 22:41:37 -07:00
E
5f8aad7355 Merge branch 'master' of https://git.tannercollin.com/tanner/3Dshock 2021-03-10 22:33:22 -07:00
E
c975432b73 🌫🎲🎰🎇📟🎏 2021-03-10 22:33:06 -07:00
be140b4c22 Add number to fake downloaded photos 2021-03-10 22:24:18 -07:00
E
3c5855ecd3 Merge branch 'master' of https://git.tannercollin.com/tanner/3Dshock 2021-03-10 20:04:21 -07:00
E
1499ee5736 🌠 2021-03-10 20:04:18 -07:00
Tanner
a07d4469c0 Add screenshot of network settings 2021-03-10 20:00:23 -07:00
Tanner
5e565f84c2 Add test for capture 2021-03-10 20:00:08 -07:00
E
b2cc6f4723 Merge branch 'master' of https://git.tannercollin.com/tanner/3Dshock 2021-03-10 19:51:34 -07:00
E
6720816a97 🗯 2021-03-10 19:51:31 -07:00
Tanner
5c15c8fcf5 Freeze requirements 2021-03-10 19:35:13 -07:00
738e688c51 Adjust capture and add logging 2021-03-10 19:22:41 -07:00
19352bf409 Add license 2021-03-10 19:22:41 -07:00
a632034751 Change statuses to ints 2021-03-10 19:22:41 -07:00
E
fa6809b507 Merge branch 'master' of https://git.tannercollin.com/tanner/3Dshock 2021-03-10 19:17:35 -07:00
E
c29a64b1cc 💅 2021-03-10 19:17:23 -07:00
d1486b61df Remove a zero 2021-03-10 17:57:31 -07:00
ecb8c1f815 Detect when the system isn't connected 2021-03-10 17:57:31 -07:00
ec8128d96a Add debug mode to simulate a capture 2021-03-10 17:57:31 -07:00
38 changed files with 600 additions and 440 deletions

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
The MIT License (MIT)
Copyright (c) 2021 Tanner and Elijah
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -1,25 +1,25 @@
{
"files": {
"main.css": "/static/css/main.df392f58.chunk.css",
"main.js": "/static/js/main.eb0b3235.chunk.js",
"main.js.map": "/static/js/main.eb0b3235.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.3a03ddd0.js",
"runtime-main.js.map": "/static/js/runtime-main.3a03ddd0.js.map",
"main.css": "/static/css/main.895ab0f5.chunk.css",
"main.js": "/static/js/main.4388b0cf.chunk.js",
"main.js.map": "/static/js/main.4388b0cf.chunk.js.map",
"runtime-main.js": "/static/js/runtime-main.8d7962eb.js",
"runtime-main.js.map": "/static/js/runtime-main.8d7962eb.js.map",
"static/css/2.015dc0ab.chunk.css": "/static/css/2.015dc0ab.chunk.css",
"static/js/2.cab625a2.chunk.js": "/static/js/2.cab625a2.chunk.js",
"static/js/2.cab625a2.chunk.js.map": "/static/js/2.cab625a2.chunk.js.map",
"static/js/3.2f629505.chunk.js": "/static/js/3.2f629505.chunk.js",
"static/js/3.2f629505.chunk.js.map": "/static/js/3.2f629505.chunk.js.map",
"static/js/2.6d12aa16.chunk.js": "/static/js/2.6d12aa16.chunk.js",
"static/js/2.6d12aa16.chunk.js.map": "/static/js/2.6d12aa16.chunk.js.map",
"static/js/3.8e9312c3.chunk.js": "/static/js/3.8e9312c3.chunk.js",
"static/js/3.8e9312c3.chunk.js.map": "/static/js/3.8e9312c3.chunk.js.map",
"index.html": "/index.html",
"static/css/2.015dc0ab.chunk.css.map": "/static/css/2.015dc0ab.chunk.css.map",
"static/css/main.df392f58.chunk.css.map": "/static/css/main.df392f58.chunk.css.map",
"static/js/2.cab625a2.chunk.js.LICENSE.txt": "/static/js/2.cab625a2.chunk.js.LICENSE.txt"
"static/css/main.895ab0f5.chunk.css.map": "/static/css/main.895ab0f5.chunk.css.map",
"static/js/2.6d12aa16.chunk.js.LICENSE.txt": "/static/js/2.6d12aa16.chunk.js.LICENSE.txt"
},
"entrypoints": [
"static/js/runtime-main.3a03ddd0.js",
"static/js/runtime-main.8d7962eb.js",
"static/css/2.015dc0ab.chunk.css",
"static/js/2.cab625a2.chunk.js",
"static/css/main.df392f58.chunk.css",
"static/js/main.eb0b3235.chunk.js"
"static/js/2.6d12aa16.chunk.js",
"static/css/main.895ab0f5.chunk.css",
"static/js/main.4388b0cf.chunk.js"
]
}

View File

@@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="3D Shock by Tanner and Elijah enterprises"/><link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"><link rel="manifest" href="/manifest.json"/><title>3D Shock!</title><link href="/static/css/2.015dc0ab.chunk.css" rel="stylesheet"><link href="/static/css/main.df392f58.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);p.length;)p.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"2f629505"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpclient=this.webpackJsonpclient||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([])</script><script src="/static/js/2.cab625a2.chunk.js"></script><script src="/static/js/main.eb0b3235.chunk.js"></script></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="3D Shock by Tanner and Elijah enterprises"/><link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>⚡</text></svg>"><link rel="manifest" href="/manifest.json"/><title>3D Shock!</title><link href="/static/css/2.015dc0ab.chunk.css" rel="stylesheet"><link href="/static/css/main.895ab0f5.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);p.length;)p.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"8e9312c3"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpclient=this.webpackJsonpclient||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([])</script><script src="/static/js/2.6d12aa16.chunk.js"></script><script src="/static/js/main.4388b0cf.chunk.js"></script></body></html>

View File

@@ -0,0 +1,2 @@
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}form{max-width:500px;-webkit-flex-direction:column;flex-direction:column}form,form label{display:-webkit-flex;display:flex;margin:auto}form label{width:100%;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}:root{--color-primary:#282c34}.App-header{background-color:#282c34;background-color:var(--color-primary);min-height:100vh;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;font-size:calc(10px + 2vmin);color:#fff}.App-link{color:#61dafb}@-webkit-keyframes App-logo-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes App-logo-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.error{color:red}.photo-wall{display:-webkit-flex;display:flex;-webkit-justify-content:center;justify-content:center;-webkit-flex-wrap:wrap;flex-wrap:wrap;margin:2rem}.dashboard-form{margin:auto}.ant-card{margin:1rem}.ant-card img{max-width:250px}.loading-bar-container{background:#282c34;background:var(--color-primary);width:100%;height:30px;min-height:30px}.loading-bar{transition:all .5s linear;background:#6f6;height:100%}.page-head{background:#282c34;background:var(--color-primary);color:#fff!important;margin-top:0;padding:1rem}.session-toolbar button{margin:0 .5rem;padding:.5rem 1rem;height:100%;font-weight:700;text-transform:uppercase;letter-spacing:.05rem}.ant-modal-content{border-radius:1rem;padding:0!important}.ant-modal-body img{border-radius:.5rem}.ant-modal-close{font-weight:700}.ant-card{border:1px solid #282c34;border:1px solid var(--color-primary);border-radius:.2rem}.ant-card-head{background:#282c34;background:var(--color-primary);color:#fff;font-weight:700;text-transform:uppercase;letter-spacing:.2rem}.session-toolbar{-webkit-justify-content:center;justify-content:center;width:60%;margin:1rem auto}.session-toolbar h3{font-weight:700;color:#fff;margin-right:1rem}.slider{width:400px;margin:auto 1rem}.toolbar{padding:.5rem;background:#282c34;background:var(--color-primary)}.client-info{-webkit-justify-content:center;justify-content:center;width:60%;margin:1rem auto}.client-info span{margin:auto 1rem}
/*# sourceMappingURL=main.895ab0f5.chunk.css.map */

View File

@@ -0,0 +1 @@
{"version":3,"sources":["webpack://src/index.css","webpack://src/App.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mJAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,yEAEF,CAEA,KAEE,eAAgB,CAEhB,6BAAsB,CAAtB,qBACF,CAEA,gBANE,oBAAa,CAAb,YAAa,CAEb,WAUF,CANA,WACE,UAAW,CAEX,0BAAmB,CAAnB,kBAAmB,CACnB,qCAA8B,CAA9B,6BAEF,CC3BA,MACE,uBACF,CAEA,YACE,wBAAsC,CAAtC,qCAAsC,CACtC,gBAAiB,CACjB,oBAAa,CAAb,YAAa,CACb,6BAAsB,CAAtB,qBAAsB,CACtB,0BAAmB,CAAnB,kBAAmB,CACnB,8BAAuB,CAAvB,sBAAuB,CACvB,4BAA6B,CAC7B,UACF,CAEA,UACE,aACF,CAEA,iCACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAPA,yBACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAEA,OACE,SACF,CAEA,YACE,oBAAa,CAAb,YAAa,CACb,8BAAuB,CAAvB,sBAAuB,CACvB,sBAAe,CAAf,cAAe,CACf,WACF,CAEA,gBACE,WACF,CAEA,UACE,WACF,CAEA,cACE,eACF,CAEA,uBACE,kBAAgC,CAAhC,+BAAgC,CAChC,UAAW,CACX,WAAY,CACZ,eACF,CAEA,aACE,yBAA2B,CAC3B,eAAmB,CACnB,WACF,CAEA,WACE,kBAAgC,CAAhC,+BAAgC,CAChC,oBAAuB,CACvB,YAAa,CACb,YACF,CAEA,wBACE,cAAgB,CAChB,kBAAoB,CACpB,WAAY,CACZ,eAAiB,CACjB,wBAAyB,CACzB,qBACF,CAEA,mBACE,kBAAmB,CACnB,mBACF,CAEA,oBACE,mBACF,CAEA,iBACE,eACF,CAEA,UACE,wBAAsC,CAAtC,qCAAsC,CACtC,mBACF,CAEA,eACE,kBAAgC,CAAhC,+BAAgC,CAChC,UAAY,CACZ,eAAiB,CACjB,wBAAyB,CACzB,oBACF,CAEA,iBACE,8BAAuB,CAAvB,sBAAuB,CACvB,SAAU,CACV,gBACF,CAEA,oBACE,eAAiB,CACjB,UAAY,CACZ,iBACF,CAEA,QACE,WAAY,CACZ,gBACF,CAEA,SACE,aAAe,CACf,kBAAgC,CAAhC,+BACF,CAEA,aACE,8BAAuB,CAAvB,sBAAuB,CACvB,SAAU,CACV,gBACF,CAEA,kBACE,gBACF","file":"main.895ab0f5.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\nform {\n display: flex;\n max-width: 500px;\n margin: auto;\n flex-direction: column;\n}\n\nform label {\n width: 100%; \n display: flex;\n flex-direction: row;\n justify-content: space-between;\n margin: auto;\n}\n\n",":root {\n --color-primary: #282c34;\n}\n\n.App-header {\n background-color: var(--color-primary);\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n.error {\n color: red;\n}\n\n.photo-wall {\n display: flex;\n justify-content: center;\n flex-wrap: wrap;\n margin: 2rem;\n}\n\n.dashboard-form {\n margin: auto;\n}\n\n.ant-card {\n margin: 1rem;\n}\n\n.ant-card img {\n max-width: 250px;\n}\n\n.loading-bar-container {\n background: var(--color-primary);\n width: 100%;\n height: 30px;\n min-height: 30px;\n}\n\n.loading-bar {\n transition: all 0.5s linear;\n background: #66ff66;\n height: 100%;\n}\n\n.page-head {\n background: var(--color-primary);\n color: white !important;\n margin-top: 0;\n padding: 1rem;\n}\n\n.session-toolbar button {\n margin: 0 0.5rem;\n padding: 0.5rem 1rem;\n height: 100%;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.05rem;\n}\n\n.ant-modal-content {\n border-radius: 1rem;\n padding: 0 !important;\n}\n\n.ant-modal-body img {\n border-radius: 0.5rem;\n}\n\n.ant-modal-close {\n font-weight: bold;\n}\n\n.ant-card {\n border: 1px solid var(--color-primary);\n border-radius: 0.2rem;\n}\n\n.ant-card-head {\n background: var(--color-primary);\n color: white;\n font-weight: bold;\n text-transform: uppercase;\n letter-spacing: 0.2rem;\n}\n\n.session-toolbar {\n justify-content: center;\n width: 60%;\n margin: 1rem auto;\n}\n\n.session-toolbar h3 {\n font-weight: bold;\n color: white;\n margin-right: 1rem;\n}\n\n.slider {\n width: 400px;\n margin: auto 1rem;\n}\n\n.toolbar {\n padding: 0.5rem;\n background: var(--color-primary);\n}\n\n.client-info {\n justify-content: center;\n width: 60%;\n margin: 1rem auto;\n}\n\n.client-info span {\n margin: auto 1rem;\n}\n"]}

View File

@@ -1,2 +0,0 @@
body{margin:0;font-family:-apple-system,BlinkMacSystemFont,"Segoe UI","Roboto","Oxygen","Ubuntu","Cantarell","Fira Sans","Droid Sans","Helvetica Neue",sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,"Courier New",monospace}form{max-width:500px;-webkit-flex-direction:column;flex-direction:column}form,form label{display:-webkit-flex;display:flex;margin:auto}form label{width:100%;-webkit-flex-direction:row;flex-direction:row;-webkit-justify-content:space-between;justify-content:space-between}.App{text-align:center}.App-logo{height:40vmin;pointer-events:none}@media (prefers-reduced-motion:no-preference){.App-logo{-webkit-animation:App-logo-spin 20s linear infinite;animation:App-logo-spin 20s linear infinite}}.App-header{background-color:#282c34;min-height:100vh;display:-webkit-flex;display:flex;-webkit-flex-direction:column;flex-direction:column;-webkit-align-items:center;align-items:center;-webkit-justify-content:center;justify-content:center;font-size:calc(10px + 2vmin);color:#fff}.App-link{color:#61dafb}@-webkit-keyframes App-logo-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}@keyframes App-logo-spin{0%{-webkit-transform:rotate(0deg);transform:rotate(0deg)}to{-webkit-transform:rotate(1turn);transform:rotate(1turn)}}.error{color:red}.photo-wall{display:-webkit-flex;display:flex;-webkit-flex-wrap:wrap;flex-wrap:wrap;margin:2rem}.ant-card{margin:1rem}.ant-card img{max-width:250px}
/*# sourceMappingURL=main.df392f58.chunk.css.map */

View File

@@ -1 +0,0 @@
{"version":3,"sources":["webpack://src/index.css","webpack://src/App.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mJAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,yEAEF,CAEA,KAEE,eAAgB,CAEhB,6BAAsB,CAAtB,qBACF,CAEA,gBANE,oBAAa,CAAb,YAAa,CAEb,WAUF,CANA,WACE,UAAW,CAEX,0BAAmB,CAAnB,kBAAmB,CACnB,qCAA8B,CAA9B,6BAEF,CC3BA,KACE,iBACF,CAEA,UACE,aAAc,CACd,mBACF,CAEA,8CACE,UACE,mDAA4C,CAA5C,2CACF,CACF,CAEA,YACE,wBAAyB,CACzB,gBAAiB,CACjB,oBAAa,CAAb,YAAa,CACb,6BAAsB,CAAtB,qBAAsB,CACtB,0BAAmB,CAAnB,kBAAmB,CACnB,8BAAuB,CAAvB,sBAAuB,CACvB,4BAA6B,CAC7B,UACF,CAEA,UACE,aACF,CAEA,iCACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAPA,yBACE,GACE,8BAAuB,CAAvB,sBACF,CACA,GACE,+BAAyB,CAAzB,uBACF,CACF,CAEA,OACE,SACF,CAEA,YACE,oBAAa,CAAb,YAAa,CACb,sBAAe,CAAf,cAAe,CACf,WACF,CAEA,UACE,WACF,CAEA,cACE,eACF","file":"main.df392f58.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n\nform {\n display: flex;\n max-width: 500px;\n margin: auto;\n flex-direction: column;\n}\n\nform label {\n width: 100%; \n display: flex;\n flex-direction: row;\n justify-content: space-between;\n margin: auto;\n}\n\n",".App {\n text-align: center;\n}\n\n.App-logo {\n height: 40vmin;\n pointer-events: none;\n}\n\n@media (prefers-reduced-motion: no-preference) {\n .App-logo {\n animation: App-logo-spin infinite 20s linear;\n }\n}\n\n.App-header {\n background-color: #282c34;\n min-height: 100vh;\n display: flex;\n flex-direction: column;\n align-items: center;\n justify-content: center;\n font-size: calc(10px + 2vmin);\n color: white;\n}\n\n.App-link {\n color: #61dafb;\n}\n\n@keyframes App-logo-spin {\n from {\n transform: rotate(0deg);\n }\n to {\n transform: rotate(360deg);\n }\n}\n\n.error {\n color: red;\n}\n\n.photo-wall {\n display: flex;\n flex-wrap: wrap;\n margin: 2rem;\n}\n\n.ant-card {\n margin: 1rem;\n}\n\n.ant-card img {\n max-width: 250px;\n}\n"]}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
(this.webpackJsonpclient=this.webpackJsonpclient||[]).push([[3],{270:function(t,n,e){"use strict";e.r(n),e.d(n,"getCLS",(function(){return v})),e.d(n,"getFCP",(function(){return y})),e.d(n,"getFID",(function(){return k})),e.d(n,"getLCP",(function(){return C})),e.d(n,"getTTFB",(function(){return P}));var i,a,r,o,c=function(t,n){return{name:t,value:void 0===n?-1:n,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},u=function(t,n){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var e=new PerformanceObserver((function(t){return t.getEntries().map(n)}));return e.observe({type:t,buffered:!0}),e}}catch(t){}},f=!1,s=function(t,n){f||"undefined"!=typeof InstallTrigger||(addEventListener("beforeunload",(function(){})),f=!0),addEventListener("visibilitychange",(function e(i){"hidden"===document.visibilityState&&(t(i),n&&removeEventListener("visibilitychange",e,!0))}),!0)},d=function(t){addEventListener("pageshow",(function(n){n.persisted&&t(n)}),!0)},m="function"==typeof WeakSet?new WeakSet:new Set,p=function(t,n,e){var i;return function(){n.value>=0&&(e||m.has(n)||"hidden"===document.visibilityState)&&(n.delta=n.value-(i||0),(n.delta||void 0===i)&&(i=n.value,t(n)))}},v=function(t,n){var e,i=c("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),e())},r=u("layout-shift",a);r&&(e=p(t,i,n),s((function(){r.takeRecords().map(a),e()})),d((function(){i=c("CLS",0),e=p(t,i,n)})))},l=-1,h=function(){return"hidden"===document.visibilityState?0:1/0},S=function(){s((function(t){var n=t.timeStamp;l=n}),!0)},g=function(){return l<0&&(l=h(),S(),d((function(){setTimeout((function(){l=h(),S()}),0)}))),{get timeStamp(){return l}}},y=function(t,n){var e,i=g(),a=c("FCP"),r=u("paint",(function(t){"first-contentful-paint"===t.name&&(r&&r.disconnect(),t.startTime<i.timeStamp&&(a.value=t.startTime,a.entries.push(t),m.add(a),e()))}));r&&(e=p(t,a,n),d((function(i){a=c("FCP"),e=p(t,a,n),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),e()}))}))})))},w={passive:!0,capture:!0},E=new Date,L=function(t,n){i||(i=n,a=t,r=new Date,F(removeEventListener),T())},T=function(){if(a>=0&&a<r-E){var t={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+a};o.forEach((function(n){n(t)})),o=[]}},b=function(t){if(t.cancelable){var n=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,n){var e=function(){L(t,n),a()},i=function(){a()},a=function(){removeEventListener("pointerup",e,w),removeEventListener("pointercancel",i,w)};addEventListener("pointerup",e,w),addEventListener("pointercancel",i,w)}(n,t):L(n,t)}},F=function(t){["mousedown","keydown","touchstart","pointerdown"].forEach((function(n){return t(n,b,w)}))},k=function(t,n){var e,r=g(),f=c("FID"),v=function(t){t.startTime<r.timeStamp&&(f.value=t.processingStart-t.startTime,f.entries.push(t),m.add(f),e())},l=u("first-input",v);e=p(t,f,n),l&&s((function(){l.takeRecords().map(v),l.disconnect()}),!0),l&&d((function(){var r;f=c("FID"),e=p(t,f,n),o=[],a=-1,i=null,F(addEventListener),r=v,o.push(r),T()}))},C=function(t,n){var e,i=g(),a=c("LCP"),r=function(t){var n=t.startTime;n<i.timeStamp&&(a.value=n,a.entries.push(t)),e()},o=u("largest-contentful-paint",r);if(o){e=p(t,a,n);var f=function(){m.has(a)||(o.takeRecords().map(r),o.disconnect(),m.add(a),e())};["keydown","click"].forEach((function(t){addEventListener(t,f,{once:!0,capture:!0})})),s(f,!0),d((function(i){a=c("LCP"),e=p(t,a,n),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),e()}))}))}))}},P=function(t){var n,e=c("TTFB");n=function(){try{var n=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,n={entryType:"navigation",startTime:0};for(var e in t)"navigationStart"!==e&&"toJSON"!==e&&(n[e]=Math.max(t[e]-t.navigationStart,0));return n}();e.value=e.delta=n.responseStart,e.entries=[n],t(e)}catch(t){}},"complete"===document.readyState?setTimeout(n,0):addEventListener("pageshow",n)}}}]);
//# sourceMappingURL=3.2f629505.chunk.js.map
(this.webpackJsonpclient=this.webpackJsonpclient||[]).push([[3],{399:function(t,n,e){"use strict";e.r(n),e.d(n,"getCLS",(function(){return v})),e.d(n,"getFCP",(function(){return y})),e.d(n,"getFID",(function(){return k})),e.d(n,"getLCP",(function(){return C})),e.d(n,"getTTFB",(function(){return P}));var i,a,r,o,c=function(t,n){return{name:t,value:void 0===n?-1:n,delta:0,entries:[],id:"v1-".concat(Date.now(),"-").concat(Math.floor(8999999999999*Math.random())+1e12)}},u=function(t,n){try{if(PerformanceObserver.supportedEntryTypes.includes(t)){var e=new PerformanceObserver((function(t){return t.getEntries().map(n)}));return e.observe({type:t,buffered:!0}),e}}catch(t){}},f=!1,s=function(t,n){f||"undefined"!=typeof InstallTrigger||(addEventListener("beforeunload",(function(){})),f=!0),addEventListener("visibilitychange",(function e(i){"hidden"===document.visibilityState&&(t(i),n&&removeEventListener("visibilitychange",e,!0))}),!0)},d=function(t){addEventListener("pageshow",(function(n){n.persisted&&t(n)}),!0)},m="function"==typeof WeakSet?new WeakSet:new Set,p=function(t,n,e){var i;return function(){n.value>=0&&(e||m.has(n)||"hidden"===document.visibilityState)&&(n.delta=n.value-(i||0),(n.delta||void 0===i)&&(i=n.value,t(n)))}},v=function(t,n){var e,i=c("CLS",0),a=function(t){t.hadRecentInput||(i.value+=t.value,i.entries.push(t),e())},r=u("layout-shift",a);r&&(e=p(t,i,n),s((function(){r.takeRecords().map(a),e()})),d((function(){i=c("CLS",0),e=p(t,i,n)})))},l=-1,h=function(){return"hidden"===document.visibilityState?0:1/0},S=function(){s((function(t){var n=t.timeStamp;l=n}),!0)},g=function(){return l<0&&(l=h(),S(),d((function(){setTimeout((function(){l=h(),S()}),0)}))),{get timeStamp(){return l}}},y=function(t,n){var e,i=g(),a=c("FCP"),r=u("paint",(function(t){"first-contentful-paint"===t.name&&(r&&r.disconnect(),t.startTime<i.timeStamp&&(a.value=t.startTime,a.entries.push(t),m.add(a),e()))}));r&&(e=p(t,a,n),d((function(i){a=c("FCP"),e=p(t,a,n),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),e()}))}))})))},w={passive:!0,capture:!0},E=new Date,L=function(t,n){i||(i=n,a=t,r=new Date,F(removeEventListener),T())},T=function(){if(a>=0&&a<r-E){var t={entryType:"first-input",name:i.type,target:i.target,cancelable:i.cancelable,startTime:i.timeStamp,processingStart:i.timeStamp+a};o.forEach((function(n){n(t)})),o=[]}},b=function(t){if(t.cancelable){var n=(t.timeStamp>1e12?new Date:performance.now())-t.timeStamp;"pointerdown"==t.type?function(t,n){var e=function(){L(t,n),a()},i=function(){a()},a=function(){removeEventListener("pointerup",e,w),removeEventListener("pointercancel",i,w)};addEventListener("pointerup",e,w),addEventListener("pointercancel",i,w)}(n,t):L(n,t)}},F=function(t){["mousedown","keydown","touchstart","pointerdown"].forEach((function(n){return t(n,b,w)}))},k=function(t,n){var e,r=g(),f=c("FID"),v=function(t){t.startTime<r.timeStamp&&(f.value=t.processingStart-t.startTime,f.entries.push(t),m.add(f),e())},l=u("first-input",v);e=p(t,f,n),l&&s((function(){l.takeRecords().map(v),l.disconnect()}),!0),l&&d((function(){var r;f=c("FID"),e=p(t,f,n),o=[],a=-1,i=null,F(addEventListener),r=v,o.push(r),T()}))},C=function(t,n){var e,i=g(),a=c("LCP"),r=function(t){var n=t.startTime;n<i.timeStamp&&(a.value=n,a.entries.push(t)),e()},o=u("largest-contentful-paint",r);if(o){e=p(t,a,n);var f=function(){m.has(a)||(o.takeRecords().map(r),o.disconnect(),m.add(a),e())};["keydown","click"].forEach((function(t){addEventListener(t,f,{once:!0,capture:!0})})),s(f,!0),d((function(i){a=c("LCP"),e=p(t,a,n),requestAnimationFrame((function(){requestAnimationFrame((function(){a.value=performance.now()-i.timeStamp,m.add(a),e()}))}))}))}},P=function(t){var n,e=c("TTFB");n=function(){try{var n=performance.getEntriesByType("navigation")[0]||function(){var t=performance.timing,n={entryType:"navigation",startTime:0};for(var e in t)"navigationStart"!==e&&"toJSON"!==e&&(n[e]=Math.max(t[e]-t.navigationStart,0));return n}();e.value=e.delta=n.responseStart,e.entries=[n],t(e)}catch(t){}},"complete"===document.readyState?setTimeout(n,0):addEventListener("pageshow",n)}}}]);
//# sourceMappingURL=3.8e9312c3.chunk.js.map

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +1,2 @@
!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);p.length;)p.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"2f629505"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpclient=this.webpackJsonpclient||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([]);
//# sourceMappingURL=runtime-main.3a03ddd0.js.map
!function(e){function t(t){for(var n,i,a=t[0],c=t[1],l=t[2],s=0,p=[];s<a.length;s++)i=a[s],Object.prototype.hasOwnProperty.call(o,i)&&o[i]&&p.push(o[i][0]),o[i]=0;for(n in c)Object.prototype.hasOwnProperty.call(c,n)&&(e[n]=c[n]);for(f&&f(t);p.length;)p.shift()();return u.push.apply(u,l||[]),r()}function r(){for(var e,t=0;t<u.length;t++){for(var r=u[t],n=!0,a=1;a<r.length;a++){var c=r[a];0!==o[c]&&(n=!1)}n&&(u.splice(t--,1),e=i(i.s=r[0]))}return e}var n={},o={1:0},u=[];function i(t){if(n[t])return n[t].exports;var r=n[t]={i:t,l:!1,exports:{}};return e[t].call(r.exports,r,r.exports,i),r.l=!0,r.exports}i.e=function(e){var t=[],r=o[e];if(0!==r)if(r)t.push(r[2]);else{var n=new Promise((function(t,n){r=o[e]=[t,n]}));t.push(r[2]=n);var u,a=document.createElement("script");a.charset="utf-8",a.timeout=120,i.nc&&a.setAttribute("nonce",i.nc),a.src=function(e){return i.p+"static/js/"+({}[e]||e)+"."+{3:"8e9312c3"}[e]+".chunk.js"}(e);var c=new Error;u=function(t){a.onerror=a.onload=null,clearTimeout(l);var r=o[e];if(0!==r){if(r){var n=t&&("load"===t.type?"missing":t.type),u=t&&t.target&&t.target.src;c.message="Loading chunk "+e+" failed.\n("+n+": "+u+")",c.name="ChunkLoadError",c.type=n,c.request=u,r[1](c)}o[e]=void 0}};var l=setTimeout((function(){u({type:"timeout",target:a})}),12e4);a.onerror=a.onload=u,document.head.appendChild(a)}return Promise.all(t)},i.m=e,i.c=n,i.d=function(e,t,r){i.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},i.r=function(e){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},i.t=function(e,t){if(1&t&&(e=i(e)),8&t)return e;if(4&t&&"object"===typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(i.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var n in e)i.d(r,n,function(t){return e[t]}.bind(null,n));return r},i.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return i.d(t,"a",t),t},i.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},i.p="/",i.oe=function(e){throw console.error(e),e};var a=this.webpackJsonpclient=this.webpackJsonpclient||[],c=a.push.bind(a);a.push=t,a=a.slice();for(var l=0;l<a.length;l++)t(a[l]);var f=c;r()}([]);
//# sourceMappingURL=runtime-main.8d7962eb.js.map

176
client/package-lock.json generated
View File

@@ -49,9 +49,6 @@
},
"engines": {
"node": ">=8"
},
"peerDependencies": {
"react": ">=16.0.0"
}
},
"node_modules/@ant-design/icons-svg": {
@@ -1618,7 +1615,6 @@
"jest-resolve": "^26.6.2",
"jest-util": "^26.6.2",
"jest-worker": "^26.6.2",
"node-notifier": "^8.0.0",
"slash": "^3.0.0",
"source-map": "^0.6.0",
"string-length": "^4.0.1",
@@ -3011,14 +3007,6 @@
"rc-util": "^5.8.1",
"scroll-into-view-if-needed": "^2.2.25",
"warning": "^4.0.3"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/ant-design"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/anymatch": {
@@ -5387,18 +5375,8 @@
"integrity": "sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg==",
"engines": {
"node": ">=0.11"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/date-fns"
}
},
"node_modules/dayjs": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz",
"integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==",
"peer": true
},
"node_modules/debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",
@@ -9601,7 +9579,6 @@
"@types/node": "*",
"anymatch": "^3.0.3",
"fb-watchman": "^2.0.0",
"fsevents": "^2.1.2",
"graceful-fs": "^4.2.4",
"jest-regex-util": "^26.0.0",
"jest-serializer": "^26.6.2",
@@ -10898,10 +10875,6 @@
"dependencies": {
"hoist-non-react-statics": "^3.3.2",
"shallowequal": "^1.0.2"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/minimalistic-assert": {
@@ -13622,10 +13595,6 @@
"dom-align": "^1.7.0",
"rc-util": "^5.3.0",
"resize-observer-polyfill": "^1.5.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-cascader": {
@@ -13638,10 +13607,6 @@
"rc-trigger": "^5.0.4",
"rc-util": "^5.0.1",
"warning": "^4.0.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-checkbox": {
@@ -13651,10 +13616,6 @@
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-collapse": {
@@ -13667,10 +13628,6 @@
"rc-motion": "^2.3.4",
"rc-util": "^5.2.1",
"shallowequal": "^1.1.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-dialog": {
@@ -13682,10 +13639,6 @@
"classnames": "^2.2.6",
"rc-motion": "^2.3.0",
"rc-util": "^5.6.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-drawer": {
@@ -13696,10 +13649,6 @@
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-util": "^5.7.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-dropdown": {
@@ -13710,10 +13659,6 @@
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6",
"rc-trigger": "^5.0.4"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/rc-field-form": {
@@ -13727,10 +13672,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">= 16.9.0",
"react-dom": ">= 16.9.0"
}
},
"node_modules/rc-image": {
@@ -13742,10 +13683,6 @@
"classnames": "^2.2.6",
"rc-dialog": "~8.5.0",
"rc-util": "^5.0.6"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-input-number": {
@@ -13756,10 +13693,6 @@
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-util": "^5.0.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-mentions": {
@@ -13773,10 +13706,6 @@
"rc-textarea": "^0.3.0",
"rc-trigger": "^5.0.4",
"rc-util": "^5.0.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-menu": {
@@ -13792,10 +13721,6 @@
"rc-util": "^5.7.0",
"resize-observer-polyfill": "^1.5.0",
"shallowequal": "^1.1.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-motion": {
@@ -13806,10 +13731,6 @@
"@babel/runtime": "^7.11.1",
"classnames": "^2.2.1",
"rc-util": "^5.2.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-notification": {
@@ -13824,10 +13745,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-overflow": {
@@ -13839,10 +13756,6 @@
"classnames": "^2.2.1",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.5.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-pagination": {
@@ -13852,10 +13765,6 @@
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-picker": {
@@ -13873,11 +13782,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"dayjs": "^1.8.30",
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-progress": {
@@ -13887,10 +13791,6 @@
"dependencies": {
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.6"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-rate": {
@@ -13904,10 +13804,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-resize-observer": {
@@ -13919,10 +13815,6 @@
"classnames": "^2.2.1",
"rc-util": "^5.0.0",
"resize-observer-polyfill": "^1.5.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-select": {
@@ -13940,10 +13832,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/rc-slider": {
@@ -13959,10 +13847,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-steps": {
@@ -13976,10 +13860,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-switch": {
@@ -13990,10 +13870,6 @@
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.1",
"rc-util": "^5.0.1"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-table": {
@@ -14009,10 +13885,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-tabs": {
@@ -14029,10 +13901,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-textarea": {
@@ -14044,10 +13912,6 @@
"classnames": "^2.2.1",
"rc-resize-observer": "^1.0.0",
"rc-util": "^5.7.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-tooltip": {
@@ -14057,10 +13921,6 @@
"dependencies": {
"@babel/runtime": "^7.11.2",
"rc-trigger": "^5.0.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-tree": {
@@ -14076,10 +13936,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/rc-tree-select": {
@@ -14092,10 +13948,6 @@
"rc-select": "^12.0.0",
"rc-tree": "^4.0.0",
"rc-util": "^5.0.5"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/rc-trigger": {
@@ -14111,10 +13963,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-upload": {
@@ -14125,10 +13973,6 @@
"@babel/runtime": "^7.10.1",
"classnames": "^2.2.5",
"rc-util": "^5.2.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-util": {
@@ -14139,10 +13983,6 @@
"@babel/runtime": "^7.12.5",
"react-is": "^16.12.0",
"shallowequal": "^1.1.0"
},
"peerDependencies": {
"react": ">=16.9.0",
"react-dom": ">=16.9.0"
}
},
"node_modules/rc-util/node_modules/react-is": {
@@ -14161,10 +14001,6 @@
},
"engines": {
"node": ">=8.x"
},
"peerDependencies": {
"react": "*",
"react-dom": "*"
}
},
"node_modules/react": {
@@ -14485,7 +14321,6 @@
"eslint-webpack-plugin": "^2.5.2",
"file-loader": "6.1.1",
"fs-extra": "^9.0.1",
"fsevents": "^2.1.3",
"html-webpack-plugin": "4.5.0",
"identity-obj-proxy": "3.0.0",
"jest": "26.6.0",
@@ -17652,10 +17487,8 @@
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz",
"integrity": "sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ==",
"dependencies": {
"chokidar": "^3.4.1",
"graceful-fs": "^4.1.2",
"neo-async": "^2.5.0",
"watchpack-chokidar2": "^2.0.1"
"neo-async": "^2.5.0"
},
"optionalDependencies": {
"chokidar": "^3.4.1",
@@ -18151,7 +17984,6 @@
"anymatch": "^2.0.0",
"async-each": "^1.0.1",
"braces": "^2.3.2",
"fsevents": "^1.2.7",
"glob-parent": "^3.1.0",
"inherits": "^2.0.3",
"is-binary-path": "^1.0.0",
@@ -24165,12 +23997,6 @@
"resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.19.0.tgz",
"integrity": "sha512-X3bf2iTPgCAQp9wvjOQytnf5vO5rESYRXlPIVcgSbtT5OTScPcsf9eZU+B/YIkKAtYr5WeCii58BgATrNitlWg=="
},
"dayjs": {
"version": "1.10.4",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz",
"integrity": "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw==",
"peer": true
},
"debug": {
"version": "4.3.1",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz",

View File

@@ -1,20 +1,9 @@
.App {
text-align: center;
}
.App-logo {
height: 40vmin;
pointer-events: none;
}
@media (prefers-reduced-motion: no-preference) {
.App-logo {
animation: App-logo-spin infinite 20s linear;
}
:root {
--color-primary: #282c34;
}
.App-header {
background-color: #282c34;
background-color: var(--color-primary);
min-height: 100vh;
display: flex;
flex-direction: column;
@@ -43,10 +32,15 @@
.photo-wall {
display: flex;
justify-content: center;
flex-wrap: wrap;
margin: 2rem;
}
.dashboard-form {
margin: auto;
}
.ant-card {
margin: 1rem;
}
@@ -54,3 +48,90 @@
.ant-card img {
max-width: 250px;
}
.loading-bar-container {
background: var(--color-primary);
width: 100%;
height: 30px;
min-height: 30px;
}
.loading-bar {
transition: all 0.5s linear;
background: #66ff66;
height: 100%;
}
.page-head {
background: var(--color-primary);
color: white !important;
margin-top: 0;
padding: 1rem;
}
.session-toolbar button {
margin: 0 0.5rem;
padding: 0.5rem 1rem;
height: 100%;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.05rem;
}
.ant-modal-content {
border-radius: 1rem;
padding: 0 !important;
}
.ant-modal-body img {
border-radius: 0.5rem;
}
.ant-modal-close {
font-weight: bold;
}
.ant-card {
border: 1px solid var(--color-primary);
border-radius: 0.2rem;
}
.ant-card-head {
background: var(--color-primary);
color: white;
font-weight: bold;
text-transform: uppercase;
letter-spacing: 0.2rem;
}
.session-toolbar {
justify-content: center;
width: 60%;
margin: 1rem auto;
}
.session-toolbar h3 {
font-weight: bold;
color: white;
margin-right: 1rem;
}
.slider {
width: 400px;
margin: auto 1rem;
}
.toolbar {
padding: 0.5rem;
background: var(--color-primary);
}
.client-info {
justify-content: center;
width: 60%;
margin: 1rem auto;
}
.client-info span {
margin: auto 1rem;
}

View File

@@ -1,23 +1,42 @@
import { Client } from '../types'
import { Client, Timings } from '../types'
import axios from 'axios'
import { message } from 'antd'
import { Status } from '../components/StatusChip'
if (process.env.NODE_ENV === 'development') {
const host = 'http://192.168.1.107:5000'
const dev = process.env.NODE_ENV === 'development'
if (dev) {
const host = 'http://192.168.1.114:5000'
axios.defaults.baseURL = host
}
const mock = false
export const createClient = async (body: Omit<Client, 'has_photos'>) => {
if (mock) return 'test'
const res = await axios.post<{ client_id: string }>(`/api/clients`, body)
return res.data.client_id
}
export const getClient = async (id: string): Promise<Client> => {
if (mock)
return {
name: 'Test Client',
has_photos: false,
email: 'test@test.test',
phone: 1234567890,
}
const res = await axios.get<Client>(`/api/clients/${id}`)
return res.data
}
export const startSession = async (clientId: string) => {
const res = await axios.post(`/api/clients/${clientId}/session`)
return res.data // session data
export const startSession = async (clientId: string, timings: Timings) => {
try {
const res = await axios.post(`/api/clients/${clientId}/session`, timings)
return res.data
} catch (err) {
message.error('Something went wrong, check connection with the machine')
return err
}
}
export const getSession = async (clientId: string) => {
@@ -31,13 +50,18 @@ export const killSession = async (clientId: string) => {
await axios.delete(`/api/clients/${clientId}/session`)
}
export const restartSession = async (clientId: string) => {
export const restartSession = async (clientId: string, timings: Timings) => {
await killSession(clientId)
await startSession(clientId)
await startSession(clientId, timings)
}
// TOOD: Get status
export const getStatus = async (): Promise<Status> => {
const res = await axios.get<{ status: Status }>('/api/status')
return res.data.status
}
// Someday
export const getClients = async (): Promise<Client[]> => {

View File

@@ -0,0 +1,23 @@
import { Button } from 'antd'
import React from 'react'
export const ScrollToTop = () => {
const handleClick = () => {
window.scrollTo(0, 0)
console.log('')
}
return (
<Button
type="link"
style={{
position: 'fixed',
right: 20,
bottom: 20,
}}
onClick={handleClick}
>
Scroll To Top
</Button>
)
}

View File

@@ -0,0 +1,131 @@
import React, { useEffect, useState } from 'react'
import { Card, Modal, Row, Select, Typography } from 'antd'
import { getSession } from '../api'
import { ScrollToTop } from './ScrollToTop'
type Props = {
clientId: string
}
export const SessionPictures = ({ clientId }: Props) => {
const [urls, setUrls] = useState<string[] | null>(null)
const [activeUrl, setActiveUrl] = useState<string | null>(null)
const [focusPhotos, setFocusPhotos] = useState<string[]>(
JSON.parse(window.localStorage.getItem('focusPhotos') || '[]'),
)
useEffect(() => {
const get = async () => {
if (urls && urls.length >= 89 * 1) {
return
}
const { photos } = await getSession(clientId)
if (photos.length) setUrls(photos)
}
const interval = setInterval(get, 250)
return () => clearInterval(interval)
}, [clientId, urls])
const closeModal = () => setActiveUrl(null)
const host =
process.env.NODE_ENV === 'development' ? 'http://192.168.1.107:5000' : ''
if (!urls?.length) return null
const photos = urls.sort((a, b) =>
a.split('_')[0].localeCompare(b.split('_')[0]),
)
const u = urls.length / 89
const handleSelect = (v: string[]) => {
console.log('SEelcted', v)
window.localStorage.setItem('focusPhotos', JSON.stringify(v))
setFocusPhotos(v)
}
const filteredPhotos = photos.filter((name) => {
const num = name.split('_')[0]
return focusPhotos.includes(num)
})
return (
<>
<Modal
visible={!!activeUrl}
onOk={closeModal}
footer={null}
onCancel={closeModal}
width="50%"
>
<img
width="100%"
onClick={closeModal}
src={`${host}/output/${clientId}/${activeUrl}`}
alt="large modal"
></img>
</Modal>
<Row
align="middle"
justify="space-around"
style={{ display: 'flex', width: '100%' }}
>
<Typography.Title style={{ margin: '0.5rem 1rem 0.7rem' }} level={3}>
Session Pictures
</Typography.Title>
<Typography.Text>{urls.length}/ 89 loaded</Typography.Text>
<Typography.Text>Select Featured Photos:</Typography.Text>
<Select
mode="multiple"
allowClear
placeholder="Please select featured"
style={{ width: '35%' }}
defaultValue={focusPhotos}
value={focusPhotos}
onChange={handleSelect}
>
{photos.map((name) => {
const val = name.split('_')[0]
return <Select.Option value={val}>{val}</Select.Option>
})}
</Select>
</Row>
<div className="loading-bar-container">
<div
className="loading-bar"
style={{
width: `${u * 100}%`,
background: `hsl(${Math.floor(u * 120)}, 90%, 70%)`,
}}
></div>
</div>
<div className="featured-photos" style={{ marginTop: '2rem' }}>
{filteredPhotos.map((src) => (
<img
onClick={() => setActiveUrl(src)}
src={`${host}/output/${clientId}/${src}`}
alt="lol"
/>
))}
</div>
<div className="photo-wall">
{photos.map((src) => (
<Card key={src} className="photo" title={src.split('_')[0]}>
<img
onClick={() => setActiveUrl(src)}
src={`${host}/output/${clientId}/${src}`}
alt="lol"
/>
</Card>
))}
</div>
<ScrollToTop />
</>
)
}

View File

@@ -0,0 +1,47 @@
import { Tag } from 'antd'
import { PresetColorType } from 'antd/lib/_util/colors'
import { useEffect, useState } from 'react'
import { getStatus } from '../api'
export enum Status {
'Standing By...',
'Warming Up...',
'Capturing Photo',
'Capturing Grid',
'Writing To Disk',
'Downloading!',
}
const colors: Partial<PresetColorType>[] = [
'lime',
'gold',
'volcano',
'magenta',
'geekblue',
]
type Props = {
poll: boolean
}
export const StatusChip = ({ poll }: Props) => {
const [status, setStatus] = useState<Status>(Status['Standing By...'])
useEffect(() => {
const get = async () => {
if (!poll) return
const status = await getStatus()
setStatus(status)
}
const interval = setInterval(get, 1000 / 4)
return () => clearInterval(interval)
}, [poll])
return (
<Tag color={colors[status]} style={{ display: 'flex' }}>
<span style={{ margin: 'auto' }}>{Status[status]}</span>
</Tag>
)
}

View File

@@ -1,28 +1,28 @@
import { Button, Divider, message, PageHeader } from 'antd'
import React from 'react'
import { Button, Divider, Form, Input, message, Row, Typography } from 'antd'
import FormItem from 'antd/lib/form/FormItem'
import { Content } from 'antd/lib/layout/layout'
import React, { FormEvent } from 'react'
import { useState } from 'react'
import { useHistory } from 'react-router-dom'
import { createClient } from '../api'
type FormData = {
name: string
email: string
phone: string
}
export const Dashboard = () => {
const history = useHistory()
const [error, setError] = useState<string | null>(null)
const [name, setName] = useState('')
const [email, setEmail] = useState('')
const [phone, setPhone] = useState('')
const [form] = Form.useForm<FormData>()
const handleReset = () => {
//
setName('')
setEmail('')
setPhone('')
form.resetFields()
}
const handleSubmit = async (e: FormEvent) => {
e.preventDefault()
if (phone.length < 10) {
const handleSubmit = async (values: FormData) => {
if (values.phone.length < 10) {
// helpful message
message.error('Check all fields!')
setError('Phone number needs to be a length of at least 10')
@@ -30,9 +30,9 @@ export const Dashboard = () => {
}
const client_id = await createClient({
name,
email,
phone: parseInt(phone),
name: values.name,
email: values.email,
phone: parseInt(values.phone.replace(/\D/g, '')),
})
history.push(`/sessions/${client_id}`)
@@ -40,47 +40,39 @@ export const Dashboard = () => {
return (
<Content>
<PageHeader
title="Dashboard"
subTitle="Enter the name, email and phone number of the subject"
></PageHeader>
<Typography.Title className="page-head" level={3}>
Dashboard
</Typography.Title>
<Divider />
<form onSubmit={handleSubmit}>
<label htmlFor="name">
Name:
<input
minLength={3}
value={name}
onChange={(e) => setName(e.target.value)}
name="name"
/>
</label>
<label htmlFor="email">
Email:
<input
value={email}
onChange={(e) => setEmail(e.target.value)}
type="email"
name="email"
/>
</label>
<label htmlFor="phone">
Phone:
<input
value={phone}
onChange={(e) => setPhone(e.target.value)}
type="tel"
name="phone"
/>
</label>
<Button danger onClick={handleReset}>
Reset
</Button>
<Button htmlType="submit" type="primary">
Start Session
</Button>
<Form
form={form}
className="dashboard-form"
onFinish={handleSubmit}
labelCol={{ span: 8 }}
wrapperCol={{ span: 16 }}
>
<Typography.Paragraph style={{ textAlign: 'center' }}>
Enter the name, email and phone number of the subject
</Typography.Paragraph>
<FormItem label="name" name="name">
<Input minLength={3} />
</FormItem>
<FormItem label="email" name="email">
<Input type="email" />
</FormItem>
<FormItem label="phone" name="phone">
<Input type="tel" minLength={10} />
</FormItem>
<Row justify="space-between">
<Button danger onClick={handleReset}>
Reset
</Button>
<Button htmlType="submit" type="primary">
Start Session
</Button>
</Row>
{error && <p className="error">{error}</p>}
</form>
</Form>
</Content>
)
}

View File

@@ -1,15 +1,17 @@
import React, { useEffect, useState } from 'react'
import { RouteComponentProps, useHistory } from 'react-router-dom'
import { getClient, killSession, restartSession, startSession } from '../api'
import { SessionPictures } from './SessionPictures'
import { SessionPictures } from '../components/SessionPictures'
import { StatusChip } from '../components/StatusChip'
import {
Button,
Divider,
Input,
InputNumber,
message,
PageHeader,
Popconfirm,
Row,
Tag,
Typography,
} from 'antd'
import { Content } from 'antd/lib/layout/layout'
import { Client } from '../types'
@@ -21,10 +23,18 @@ export const Session = (props: Props) => {
const { clientId } = props.match.params
const [client, setClient] = useState<Client | null>(null)
const [active, setActive] = useState(false)
const [lightTime, setLightTime] = useState(
parseInt(window.localStorage.getItem('lightTime') || '5000'),
)
const handleTimingUpdate = (n: number) => {
window.localStorage.setItem('lightTime', n.toString())
setLightTime(n)
}
const handleStartSession = async () => {
message.loading('Photo sequence starting! Stand by...')
await startSession(clientId)
await startSession(clientId, { light_time: lightTime })
setActive(true)
}
@@ -33,7 +43,7 @@ export const Session = (props: Props) => {
message.loading(
'Deleting photos & restarting capture sequence! Stand by...',
)
await restartSession(clientId)
await restartSession(clientId, { light_time: lightTime })
setActive(true)
}
@@ -59,13 +69,26 @@ export const Session = (props: Props) => {
return (
<Content>
<PageHeader
ghost={false}
onBack={() => history.goBack()}
title={`Session for ${clientId}`}
tags={active ? <Tag color="lime">Active</Tag> : <Tag>Inactive</Tag>}
subTitle={`session has ${active ? 'started' : 'not started'}`}
extra={[
<Typography.Title className="page-head" level={3}>
Session View
</Typography.Title>
<Row className="client-info">
<Typography.Text>
<strong>Name:</strong> {client?.name}
</Typography.Text>
<Typography.Text>
<strong>Email:</strong> {client?.email}
</Typography.Text>
<Typography.Text>
<strong>Phone:</strong> {client?.phone}
</Typography.Text>
</Row>
<div className="toolbar">
<Row justify="center" className="session-toolbar">
<Button key="finish" onClick={handleExit}>
Back To Dashboard
</Button>
<Button
key="startsession"
disabled={active}
@@ -73,8 +96,9 @@ export const Session = (props: Props) => {
onClick={handleStartSession}
>
Capture
</Button>,
</Button>
<Popconfirm
disabled={!active}
key="retry"
title="Re-capture set?"
onConfirm={handleRestartSession}
@@ -82,28 +106,34 @@ export const Session = (props: Props) => {
<Button type="default" disabled={!active}>
Retry Capture
</Button>
</Popconfirm>,
</Popconfirm>
<Popconfirm
key="nuke"
disabled={!active}
title="Delete all photos and return to dashboard?"
onConfirm={handleNuke}
>
<Button danger disabled={!active}>
Abort Session
</Button>
</Popconfirm>,
<Button
key="finish"
ghost
type="primary"
disabled={!active}
onClick={handleExit}
>
Finish Session
</Button>,
]}
></PageHeader>
<Divider />
</Popconfirm>
<StatusChip poll={true} />
</Row>
<Row className="session-toolbar">
<h3>Light Duration (ms)</h3>
<InputNumber value={lightTime} onChange={handleTimingUpdate} />
<Input
className="slider"
type="range"
onChange={(e) => handleTimingUpdate(parseInt(e.target.value))}
value={lightTime}
min={500}
max={10000}
step={500}
/>
</Row>
</div>
<Row className="controls">
{active && <SessionPictures clientId={clientId} />}
</Row>

View File

@@ -1,84 +0,0 @@
import React, { useEffect, useState } from 'react'
import { Card, message, Modal, PageHeader, Spin } from 'antd'
import { getSession } from '../api'
type Props = {
clientId: string
}
export const SessionPictures = ({ clientId }: Props) => {
const [urls, setUrls] = useState<string[] | null>(null)
const [activeUrl, setActiveUrl] = useState<string | null>(null)
const [loading, setLoading] = useState(true)
const handleSync = async () => {
message.info('Syncing photos...')
const { photos } = await getSession(clientId)
if (photos.length) setUrls(photos)
}
useEffect(() => {
const get = async () => {
if (urls && urls.length >= 89 * 2) {
setLoading(false)
return
}
const { photos } = await getSession(clientId)
if (photos.length) setUrls(photos)
}
const interval = setInterval(get, 250)
return () => clearInterval(interval)
}, [clientId, urls])
const closeModal = () => setActiveUrl(null)
const host =
process.env.NODE_ENV === 'development' ? 'http://192.168.1.107:5000' : ''
if (!urls?.length) return null
return (
<>
<Modal
visible={!!activeUrl}
onOk={closeModal}
cancelText={null}
onCancel={closeModal}
width="50%"
>
<img
width="100%"
onClick={closeModal}
src={`${host}/output/${clientId}/${activeUrl}`}
alt="large image"
></img>
</Modal>
<PageHeader
title="Session Pictures"
subTitle={`${urls.length}/${89 * 2} loaded`}
></PageHeader>
<div className="photo-wall">
{urls ? (
urls
.sort((a, b) => a.split('_')[0].localeCompare(b.split('_')[0]))
.map((src) => (
<Card className="photo" title={src.split('_')[0]}>
<img
onClick={() => setActiveUrl(src)}
key={src}
id={src}
src={`${host}/output/${clientId}/${src}`}
alt="lol"
/>
</Card>
))
) : (
<Spin />
)}
</div>
</>
)
}

View File

@@ -8,3 +8,7 @@ export type Client = {
export type Session = {
timestamp: number
}
export type Timings = {
light_time: number // 5000
}

View File

@@ -1364,7 +1364,6 @@
"jest-resolve" "^26.6.2"
"jest-util" "^26.6.2"
"jest-worker" "^26.6.2"
"node-notifier" "^8.0.0"
"slash" "^3.0.0"
"source-map" "^0.6.0"
"string-length" "^4.0.1"
@@ -3385,7 +3384,6 @@
"anymatch" "^2.0.0"
"async-each" "^1.0.1"
"braces" "^2.3.2"
"fsevents" "^1.2.7"
"glob-parent" "^3.1.0"
"inherits" "^2.0.3"
"is-binary-path" "^1.0.0"
@@ -4140,11 +4138,6 @@
"resolved" "https://registry.npmjs.org/date-fns/-/date-fns-2.19.0.tgz"
"version" "2.19.0"
"dayjs@^1.8.30":
"integrity" "sha512-RI/Hh4kqRc1UKLOAf/T5zdMMX5DQIlDxwUe3wSyMMnEbGunnpENCdbUgM+dW7kXidZqCttBrmw7BhN4TMddkCw=="
"resolved" "https://registry.npmjs.org/dayjs/-/dayjs-1.10.4.tgz"
"version" "1.10.4"
"debug@^2.2.0":
"integrity" "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA=="
"resolved" "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz"
@@ -6667,7 +6660,6 @@
"@types/node" "*"
"anymatch" "^3.0.3"
"fb-watchman" "^2.0.0"
"fsevents" "^2.1.2"
"graceful-fs" "^4.2.4"
"jest-regex-util" "^26.0.0"
"jest-serializer" "^26.6.2"
@@ -9757,7 +9749,7 @@
"strip-ansi" "6.0.0"
"text-table" "0.2.0"
"react-dom@*", "react-dom@^17.0.1", "react-dom@>= 16.9.0", "react-dom@>=16.9.0":
"react-dom@^17.0.1":
"integrity" "sha512-6eV150oJZ9U2t9svnsspTMrWNyHc6chX0KzDeAOXftRa8bNeOKTTfCJ7KorIwenkHd2xqVTBTCZd79yk/lx/Ug=="
"resolved" "https://registry.npmjs.org/react-dom/-/react-dom-17.0.1.tgz"
"version" "17.0.1"
@@ -9863,7 +9855,6 @@
"eslint-webpack-plugin" "^2.5.2"
"file-loader" "6.1.1"
"fs-extra" "^9.0.1"
"fsevents" "^2.1.3"
"html-webpack-plugin" "4.5.0"
"identity-obj-proxy" "3.0.0"
"jest" "26.6.0"
@@ -9897,7 +9888,7 @@
optionalDependencies:
"fsevents" "^2.1.3"
"react@*", "react@^17.0.1", "react@>= 16.9.0", "react@>=16.0.0", "react@>=16.9.0":
"react@^17.0.1":
"integrity" "sha512-lG9c9UuMHdcAexXtigOZLX8exLWkW0Ku29qPRU8uhF2R9BN96dLCt0psvzPLlHc5OWkgymP3qwTRgbnw5BKx3w=="
"resolved" "https://registry.npmjs.org/react/-/react-17.0.1.tgz"
"version" "17.0.1"
@@ -12018,10 +12009,8 @@
"resolved" "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz"
"version" "1.7.5"
dependencies:
"chokidar" "^3.4.1"
"graceful-fs" "^4.1.2"
"neo-async" "^2.5.0"
"watchpack-chokidar2" "^2.0.1"
optionalDependencies:
"chokidar" "^3.4.1"
"watchpack-chokidar2" "^2.0.1"

BIN
network-settings.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

View File

@@ -28,3 +28,7 @@ def trigger_capture():
sock.sendto(SEND.encode('utf-8'), (MCAST_GRP, MCAST_PORT))
sock.close()
print('Sent.')
if __name__ == '__main__':
print('Triggering test capture...')
trigger_capture()

View File

@@ -5,7 +5,18 @@ import paramiko
import time
paramiko.util.log_to_file('paramiko.log')
def fake_download(ip, dest):
import requests, random
num = ip.split('.')[3]
r = requests.get('https://picsum.photos/400/300?random=' + num)
time.sleep(random.uniform(2, 10))
with open(dest / (num + '_420.jpg'), 'wb') as f:
f.write(r.content)
def download(ip, dest):
if settings.DEBUG:
fake_download(ip, dest)
print('Downloading from', ip)
port = 22

View File

@@ -1,18 +1,31 @@
import os
import json
import time
from datetime import datetime
from pathlib import Path
from flask import Flask, request, abort, send_from_directory
from flask_cors import CORS
import power, capture, download
import power, capture, download, settings
import logging
log = logging.getLogger('werkzeug')
if not settings.DEBUG:
log.setLevel(logging.ERROR)
build_folder = Path('../client/build')
output_folder = Path('./output')
app = Flask(__name__, static_folder=str(build_folder), static_url_path='')
CORS(app)
status = 'Standby'
STANDBY = 0
WARMUP = 1
CAPTURING_PHOTO = 2
CAPTURING_GRID = 3
WRITING = 4
DOWNLOADING = 5
status = STANDBY
@app.route('/api/status', methods=['GET'])
def status_get():
@@ -21,24 +34,27 @@ def status_get():
@app.route('/api/clients', methods=['POST'])
def clients_post():
content = request.json
print('Recieved:', content)
phone = str(content['phone'])
for i in range(1, 100):
suffix = str(i).zfill(3)
suffix = str(i).zfill(2)
folder = phone + '_' + suffix
path = output_folder / folder
if not path.exists():
break
content['date'] = datetime.now().strftime('%Y-%m-%d')
content['time'] = datetime.now().strftime('%H:%M:%S')
path.mkdir()
info_file = path / 'info.json'
info_file = path / 'info.txt'
info_file.touch()
info_file.write_text(json.dumps(content, indent=4))
client_id = folder
print('POST client:', content, 'cid:', client_id)
return {'client_id': client_id}
@app.route('/api/clients/<cid>', methods=['GET'])
@@ -49,12 +65,13 @@ def clients_get(cid):
if not path.exists():
abort(404)
info_file = path / 'info.json'
info_file = path / 'info.txt'
info_text = info_file.read_text()
res = json.loads(info_text)
photo_glob = path.glob('*.jpg')
res['has_photos'] = bool(list(photo_glob))
print('GET client:', cid, 'res:', res)
return res
@app.route('/api/clients/<cid>/session', methods=['GET'])
@@ -84,12 +101,17 @@ def session_delete(cid):
for p in photo_glob:
p.unlink()
print('DELETE session:', cid)
return ''
@app.route('/api/clients/<cid>/session', methods=['POST'])
def session_post(cid):
content = request.json
light_time = content.get('light_time', 5000)
global status
print('POST session:', cid)
folder = cid
path = output_folder / cid
@@ -97,35 +119,38 @@ def session_post(cid):
abort(404)
# go through the photo taking process
status = 'Warming up'
# warmup
power.lights_on()
time.sleep(4)
power.lights_off()
time.sleep(0.5)
status = 'Capturing'
try:
# warmup
status = WARMUP
power.lights_on()
time.sleep(2)
power.lights_off()
time.sleep(1)
except BaseException as e:
print('Problem with lights: {} - {}'.format(e.__class__.__name__, str(e)))
print()
print('Are you sure the system is connected?')
print()
abort(500)
# capture
status = CAPTURING_PHOTO
power.lights_on()
time.sleep(0.25)
time.sleep(0.1)
capture.trigger_capture()
time.sleep(1)
power.grid_on()
time.sleep(0.25)
capture.trigger_capture()
time.sleep(1)
power.grid_off()
time.sleep(light_time / 1000)
power.lights_off()
status = 'Writing to files'
status = WRITING
time.sleep(max(5 - light_time / 1000, 1))
status = DOWNLOADING
download.download_all_photos(path)
time.sleep(3)
status = 'Downloading'
download.download_all_photos(path)
status = 'Standby'
status = STANDBY
print('Finished.')
return ''
@app.route('/')

View File

@@ -3,6 +3,8 @@ import settings
import time
def np_02B_api(ip, username, password, is_on):
if settings.DEBUG: return
if is_on:
endpoint = '/cmd.cgi?grp=0'
else:

View File

@@ -1,5 +1,36 @@
certifi==2020.12.5
chardet==4.0.0
idna==2.10
requests==2.25.1
urllib3==1.26.3
appdirs==1.4.3
bcrypt==3.2.0
CacheControl==0.12.6
certifi==2019.11.28
cffi==1.14.5
chardet==3.0.4
click==7.1.2
colorama==0.4.3
contextlib2==0.6.0
cryptography==3.4.6
distlib==0.3.0
distro==1.4.0
Flask==1.1.2
Flask-Cors==3.0.10
html5lib==1.0.1
idna==2.8
ipaddr==2.2.0
itsdangerous==1.1.0
Jinja2==2.11.3
lockfile==0.12.2
MarkupSafe==1.1.1
msgpack==0.6.2
packaging==20.3
paramiko==2.7.2
pep517==0.8.2
progress==1.5
pycparser==2.20
PyNaCl==1.4.0
pyparsing==2.4.6
pytoml==0.1.21
requests==2.22.0
retrying==1.3.3
six==1.14.0
urllib3==1.25.8
webencodings==0.5.1
Werkzeug==1.0.1

View File

@@ -1,3 +1,6 @@
import os
DEBUG = os.environ.get('FLASK_ENV', None) == 'development'
LIGHT_IP = '192.168.99.25'
LIGHT_USER = 'admin'
LIGHT_PASS = 'admin'