Restructure the js app (#243)
* prettier * linter * add prettier, and format the code * remove common, merge it with frontend * refactor the app * better lint and code fix * travis for the frontend app * travis build script Signed-off-by: Daniel Maricic <daniel@woss.io> * lint and build * update the README.md Signed-off-by: Daniel Maricic <daniel@woss.io> * change the commands to reflect refactor Signed-off-by: Daniel Maricic <daniel@woss.io> * prettier and tslint are friends Signed-off-by: Daniel Maricic <daniel@woss.io> * code that wasn't linted properly before Signed-off-by: Daniel Maricic <daniel@woss.io> * prettier rc got deleted * workgin on making the travis pass Signed-off-by: Daniel Maricic <daniel@woss.io> * travis build please? Signed-off-by: Daniel Maricic <daniel@woss.io> * update readme.md Signed-off-by: Daniel Maricic <daniel@woss.io> * dockerfile deleted from fronted - out of scope Signed-off-by: Daniel Maricic <daniel@woss.io> * remove Signed-off-by: Daniel Maricic <daniel@woss.io> * tsconfig Signed-off-by: Daniel Maricic <daniel@woss.io> * found the reason why EOL wasn't happening Signed-off-by: Daniel Maricic <daniel@woss.io> * type for the event in the ConnectionInput as suggested * strictnullCheck to true * noImplicitAny * noUnusedParams * AfgHandling * update * fix Location.tsx * Few minor fixes * remove connection input and revert to original * esnext fixes the imports for icons and non default `* as ` * update to the tsconfig.test.json don't use commonjs please * fixed wrong comment for TIMEOUT_BASE * return totem.svg and type decraration of maybe Signed-off-by: Daniel Maricic <daniel@woss.io> Co-authored-by: Will <w.kopp@kigroup.de>
@@ -1,4 +1,8 @@
|
||||
[*.{js,ts,tsx,json,css}]
|
||||
root = true
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
|
||||
@@ -7,10 +7,10 @@ backend/target
|
||||
node_modules
|
||||
|
||||
# testing
|
||||
packages/*/coverage
|
||||
coverage
|
||||
|
||||
# production
|
||||
packages/*/build
|
||||
build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
|
||||
@@ -30,6 +30,7 @@ before_script:
|
||||
|
||||
script:
|
||||
- yarn
|
||||
- yarn check:all
|
||||
- yarn build:all
|
||||
- cd backend && cargo test
|
||||
- cd frontend && yarn
|
||||
- yarn test
|
||||
- yarn check
|
||||
- yarn build
|
||||
|
||||
@@ -1,16 +1,18 @@
|
||||
# Polkadot Telemetry
|
||||
|
||||
## Getting Started
|
||||
|
||||
To run the backend, you will need `cargo` to build the binary. We recommend using [`rustup`](https://rustup.rs/).
|
||||
|
||||
To run the frontend make sure to grab the latest stable version of node and install dependencies before doing anything:
|
||||
|
||||
```
|
||||
```sh
|
||||
nvm install stable
|
||||
yarn
|
||||
```
|
||||
|
||||
### Terminal 1 - Backend
|
||||
|
||||
```
|
||||
cd backend
|
||||
cargo build --release
|
||||
@@ -20,35 +22,45 @@ cargo build --release
|
||||
By default, telemetry will listen on the local interface only (127.0.0.1) on port 8000. You may change both those values:
|
||||
|
||||
Use another port:
|
||||
|
||||
```
|
||||
PORT=8123 telemetry
|
||||
```
|
||||
|
||||
You may also change the the listening interface. This is especially required if you are using docker:
|
||||
|
||||
```
|
||||
BIND=0.0.0.0 telemetry
|
||||
```
|
||||
|
||||
### Terminal 2 - Frontend
|
||||
```
|
||||
yarn start:frontend
|
||||
|
||||
```sh
|
||||
cd frontend
|
||||
yarn
|
||||
yarn start
|
||||
```
|
||||
|
||||
### Terminal 3 - Node
|
||||
|
||||
Follow up installation instructions from the [Polkadot repo](https://github.com/paritytech/polkadot)
|
||||
|
||||
```
|
||||
```sh
|
||||
./target/release/polkadot --dev --telemetry-url ws://localhost:8000/submit
|
||||
```
|
||||
|
||||
### Run via Docker
|
||||
|
||||
To run via docker make sure that you have Docker Desktop
|
||||
- If you dont you can download for you OS here [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
```
|
||||
|
||||
- If you dont you can download for you OS here [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||
|
||||
```sh
|
||||
docker-compose up --build -d
|
||||
```
|
||||
- -d stands for detach, if you would like to see logs i recommend using [Kitmatic](https://kitematic.com/) or dont use the -d
|
||||
- --build will build the images and rebuild, but this is not required everytime
|
||||
- If you want to makes UI changes, there is no need to rebuild the image as the files are being copied in via volumes.
|
||||
|
||||
- -d stands for detach, if you would like to see logs i recommend using [Kitmatic](https://kitematic.com/) or don't use the -d
|
||||
- --build will build the images and rebuild, but this is not required every time
|
||||
- If you want to makes UI changes, there is no need to rebuild the image as the files are being copied in via volumes.
|
||||
|
||||
Now navigate to localhost:3000 in your browser to view the app.
|
||||
|
||||
@@ -25,8 +25,8 @@
|
||||
"blakejs": "^1.1.0",
|
||||
"husky": "^4.2.3",
|
||||
"lint-staged": "^10.1.0",
|
||||
"react": "16.4.0",
|
||||
"react-dom": "16.4.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
"react-measure": "^2.3.0",
|
||||
"react-scripts-ts": "2.17.0",
|
||||
"react-svg": "^4.1.1",
|
||||
@@ -56,10 +56,10 @@
|
||||
"jest": "^23.6.0",
|
||||
"jest-localstorage-mock": "^2.2.0",
|
||||
"mock-socket": "^8.0.2",
|
||||
"prettier": "^2.0.2",
|
||||
"react-test-renderer": "^16.5.2",
|
||||
"ts-jest": "^23.10.2",
|
||||
"tslint-config-prettier": "^1.18.0",
|
||||
"prettier": "^2.0.2",
|
||||
"tslint-plugin-prettier": "^2.3.0",
|
||||
"typescript": "^2.9.2"
|
||||
},
|
||||
@@ -68,4 +68,4 @@
|
||||
"pretty:fix"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,19 @@
|
||||
// Jdenticon 2.1.1 | jdenticon.com | MIT licensed | (c) 2014-2018 Daniel Mester Pirttijärvi
|
||||
(function(q,y,z){var t=z(q,q.jQuery);"undefined"!==typeof module&&"exports"in module?module.exports=t:"function"===typeof define&&define.amd?define([],function(){return t}):q[y]=t})(this,"jdenticon",function(q,y){function z(a,b,c){for(var d=document.createElementNS("http://www.w3.org/2000/svg",b),f=2;f+1<arguments.length;f+=2)d.setAttribute(arguments[f],arguments[f+1]);a.appendChild(d)}function t(a){this.b=Math.min(Number(a.getAttribute("width"))||100,Number(a.getAttribute("height"))||100);for(this.a=
|
||||
a;a.firstChild;)a.removeChild(a.firstChild);a.setAttribute("viewBox","0 0 "+this.b+" "+this.b);a.setAttribute("preserveAspectRatio","xMidYMid meet")}function K(a){this.b=a;this.a='\x3csvg xmlns\x3d"http://www.w3.org/2000/svg" width\x3d"'+a+'" height\x3d"'+a+'" viewBox\x3d"0 0 '+a+" "+a+'" preserveAspectRatio\x3d"xMidYMid meet"\x3e'}function N(a){return function(a){for(var b=[],d=0;d<a.length;d++)for(var f=a[d],e=28;0<=e;e-=4)b.push((f>>>e&15).toString(16));return b.join("")}(function(a){for(var b=
|
||||
1732584193,d=4023233417,f=2562383102,e=271733878,h=3285377520,k=[b,d,f,e,h],g=0;g<a.length;g++){for(var u=a[g],l=16;80>l;l++){var A=u[l-3]^u[l-8]^u[l-14]^u[l-16];u[l]=A<<1|A>>>31}for(l=0;80>l;l++)A=(b<<5|b>>>27)+(20>l?(d&f^~d&e)+1518500249:40>l?(d^f^e)+1859775393:60>l?(d&f^d&e^f&e)+2400959708:(d^f^e)+3395469782)+h+u[l],h=e,e=f,f=d<<30|d>>>2,d=b,b=A|0;k[0]=b=k[0]+b|0;k[1]=d=k[1]+d|0;k[2]=f=k[2]+f|0;k[3]=e=k[3]+e|0;k[4]=h=k[4]+h|0}return k}(function(a){function b(a,b){for(var c=[],d=-1,e=0;e<b;e++)d=
|
||||
e/4|0,c[d]=(c[d]||0)+(f[a+e]<<8*(3-(e&3)));for(;16>++d;)c[d]=0;return c}var d=encodeURI(a),f=[];a=0;var e,h=[];for(e=0;e<d.length;e++){if("%"==d[e]){var k=r(d,e+1,2);e+=2}else k=d.charCodeAt(e);f[a++]=k}f[a++]=128;for(e=0;e+64<=a;e+=64)h.push(b(e,64));d=a-e;e=b(e,d);64<d+8&&(h.push(e),e=b(0,0));e[15]=8*a-8;h.push(e);return h}(a)))}function E(a,b){var c=a.canvas.width,d=a.canvas.height;a.save();this.b=a;b?this.a=b:(this.a=Math.min(c,d),a.translate((c-this.a)/2|0,(d-this.a)/2|0));a.clearRect(0,0,this.a,
|
||||
this.a)}function v(a){a|=0;return 0>a?"00":16>a?"0"+a.toString(16):256>a?a.toString(16):"ff"}function F(a,b,c){c=0>c?c+6:6<c?c-6:c;return v(255*(1>c?a+(b-a)*c:3>c?b:4>c?a+(b-a)*(4-c):a))}function O(a){"undefined"!=typeof MutationObserver&&(new MutationObserver(function(b){for(var c=0;c<b.length;c++){for(var d=b[c],f=d.addedNodes,e=0;f&&e<f.length;e++){var h=f[e];if(1==h.nodeType)if(g.w(h))a(h);else{h=h.querySelectorAll(g.A);for(var k=0;k<h.length;k++)a(h[k])}}"attributes"==d.type&&g.w(d.target)&&
|
||||
a(d.target)}})).observe(document.body,{childList:!0,attributes:!0,attributeFilter:[g.o,g.s,"width","height"],subtree:!0})}function r(a,b,c){return parseInt(a.substr(b,c),16)}function p(a){return(10*a+.5|0)/10}function L(){this.j=""}function G(a){this.b={};this.h=a;this.a=a.b}function M(a){this.h=a;this.c=w.a}function P(a,b){a=b.O(a);return[m.i(a,b.H,b.G(0)),m.i(a,b.v,b.u(.5)),m.i(a,b.H,b.G(1)),m.i(a,b.v,b.u(1)),m.i(a,b.v,b.u(0))]}function B(a,b){this.x=a;this.y=b}function w(a,b,c,d){this.b=a;this.c=
|
||||
b;this.h=c;this.a=d}function H(a,b,c,d,f,e,h){function k(e,f,k,h,g){h=h?r(b,h,1):0;f=f[r(b,k,1)%f.length];a.D(p[n[e]]);for(e=0;e<g.length;e++)m.c=new w(c+g[e][0]*l,d+g[e][1]*l,l,h++%4),f(m,l,e);a.F()}function g(a){if(0<=a.indexOf(q))for(var b=0;b<a.length;b++)if(0<=n.indexOf(a[b]))return!0}h.C&&a.m(h.C);e=.5+f*(void 0===e?.08:e)|0;f-=2*e;var m=new M(a),l=0|f/4;c+=0|e+f/2-2*l;d+=0|e+f/2-2*l;var p=P(r(b,-7)/268435455,h),n=[];for(f=0;3>f;f++){var q=r(b,8+f,1)%p.length;if(g([0,4])||g([2,3]))q=1;n.push(q)}k(0,
|
||||
I.I,2,3,[[1,0],[2,0],[2,3],[1,3],[0,1],[3,1],[3,2],[0,2]]);k(1,I.I,4,5,[[0,0],[3,0],[3,3],[0,3]]);k(2,I.M,1,null,[[1,1],[2,1],[2,2],[1,2]]);a.finish()}function J(){function a(a,b){var d=c[a];d&&1<d.length||(d=b);return function(a){a=d[0]+a*(d[1]-d[0]);return 0>a?0:1<a?1:a}}var b=n.config||q.jdenticon_config||{},c=b.lightness||{},d=b.saturation||{},f="color"in d?d.color:d;d=d.grayscale;return{O:function(a){var c=b.hues,d;c&&0<c.length&&(d=c[0|.999*a*c.length]);return"number"==typeof d?(d/360%1+1)%
|
||||
1:a},v:"number"==typeof f?f:.5,H:"number"==typeof d?d:0,u:a("color",[.4,.8]),G:a("grayscale",[.3,.9]),C:m.parse(b.backColor)}}function C(a){return/^[0-9a-f]{11,}$/i.test(a)&&a}function D(a){return N(null==a?"":""+a)}function x(a,b,c){if("string"===typeof a){if(g.J){a=document.querySelectorAll(a);for(var d=0;d<a.length;d++)x(a[d],b,c)}}else if(d=g.w(a))if(b=C(b)||null!=b&&D(b)||C(a.getAttribute(g.s))||a.hasAttribute(g.o)&&D(a.getAttribute(g.o)))a=d==g.B?new G(new t(a)):new E(a.getContext("2d")),H(a,
|
||||
b,0,0,a.a,c,J())}function n(){g.J&&x(g.A)}function Q(){var a=(n.config||q.jdenticon_config||{}).replaceMode;"never"!=a&&(n(),"observe"==a&&O(x))}t.prototype={m:function(a,b){b&&z(this.a,"rect","width","100%","height","100%","fill",a,"opacity",b)},c:function(a,b){z(this.a,"path","fill",a,"d",b)}};K.prototype={m:function(a,b){b&&(this.a+='\x3crect width\x3d"100%" height\x3d"100%" fill\x3d"'+a+'" opacity\x3d"'+b.toFixed(2)+'"/\x3e')},c:function(a,b){this.a+='\x3cpath fill\x3d"'+a+'" d\x3d"'+b+'"/\x3e'},
|
||||
toString:function(){return this.a+"\x3c/svg\x3e"}};var g={B:1,L:2,s:"data-jdenticon-hash",o:"data-jdenticon-value",J:"undefined"!==typeof document&&"querySelectorAll"in document,w:function(a){if(a){var b=a.tagName;if(/svg/i.test(b))return g.B;if(/canvas/i.test(b)&&"getContext"in a)return g.L}}};g.A="["+g.s+"],["+g.o+"]";E.prototype={m:function(a){var b=this.b,c=this.a;b.fillStyle=m.K(a);b.fillRect(0,0,c,c)},D:function(a){this.b.fillStyle=m.K(a);this.b.beginPath()},F:function(){this.b.fill()},f:function(a){var b=
|
||||
this.b,c;b.moveTo(a[0].x,a[0].y);for(c=1;c<a.length;c++)b.lineTo(a[c].x,a[c].y);b.closePath()},g:function(a,b,c){var d=this.b;b/=2;d.moveTo(a.x+b,a.y+b);d.arc(a.x+b,a.y+b,b,0,2*Math.PI,c);d.closePath()},finish:function(){this.b.restore()}};var m={P:function(a,b,c){return"#"+v(a)+v(b)+v(c)},parse:function(a){if(/^#[0-9a-f]{3,8}$/i.test(a)){if(6>a.length){var b=a[1],c=a[2],d=a[3];a=a[4]||"";return"#"+b+b+c+c+d+d+a+a}if(7==a.length||8<a.length)return a}},K:function(a){var b=r(a,7,2);return isNaN(b)?
|
||||
a:"rgba("+r(a,1,2)+","+r(a,3,2)+","+r(a,5,2)+","+(b/255).toFixed(2)+")"},N:function(a,b,c){if(0==b)return a=v(255*c),"#"+a+a+a;b=.5>=c?c*(b+1):c+b-c*b;c=2*c-b;return"#"+F(c,b,6*a+2)+F(c,b,6*a)+F(c,b,6*a-2)},i:function(a,b,c){var d=[.55,.5,.5,.46,.6,.55,.55][6*a+.5|0];return m.N(a,b,.5>c?c*d*2:d+(c-.5)*(1-d)*2)}},I={M:[function(a,b){var c=.42*b;a.f([0,0,b,0,b,b-2*c,b-c,b,0,b])},function(a,b){var c=0|.5*b;a.b(b-c,0,c,0|.8*b,2)},function(a,b){var c=0|b/3;a.a(c,c,b-c,b-c)},function(a,b){var c=.1*b,d=
|
||||
6>b?1:8>b?2:0|.25*b;c=1<c?0|c:.5<c?1:c;a.a(d,d,b-c-d,b-c-d)},function(a,b){var c=0|.15*b,d=0|.5*b;a.g(b-d-c,b-d-c,d)},function(a,b){var c=.1*b,d=4*c;3<d&&(d|=0);a.a(0,0,b,b);a.f([d,d,b-c,d,d+(b-d-c)/2,b-c],!0)},function(a,b){a.f([0,0,b,0,b,.7*b,.4*b,.4*b,.7*b,b,0,b])},function(a,b){a.b(b/2,b/2,b/2,b/2,3)},function(a,b){a.a(0,0,b,b/2);a.a(0,b/2,b/2,b/2);a.b(b/2,b/2,b/2,b/2,1)},function(a,b){var c=.14*b,d=4>b?1:6>b?2:0|.35*b;c=8>b?c:0|c;a.a(0,0,b,b);a.a(d,d,b-d-c,b-d-c,!0)},function(a,b){var c=.12*
|
||||
b,d=3*c;a.a(0,0,b,b);a.g(d,d,b-c-d,!0)},function(a,b){a.b(b/2,b/2,b/2,b/2,3)},function(a,b){var c=.25*b;a.a(0,0,b,b);a.l(c,c,b-c,b-c,!0)},function(a,b,c){var d=.4*b;c||a.g(d,d,1.2*b)}],I:[function(a,b){a.b(0,0,b,b,0)},function(a,b){a.b(0,b/2,b,b/2,0)},function(a,b){a.l(0,0,b,b)},function(a,b){var c=b/6;a.g(c,c,b-2*c)}]};L.prototype={f:function(a){for(var b="M"+p(a[0].x)+" "+p(a[0].y),c=1;c<a.length;c++)b+="L"+p(a[c].x)+" "+p(a[c].y);this.j+=b+"Z"},g:function(a,b,c){c=c?0:1;var d=p(b/2),f=p(b);this.j+=
|
||||
"M"+p(a.x)+" "+p(a.y+b/2)+"a"+d+","+d+" 0 1,"+c+" "+f+",0a"+d+","+d+" 0 1,"+c+" "+-f+",0"}};G.prototype={m:function(a){a=/^(#......)(..)?/.exec(a);this.h.m(a[1],a[2]?r(a[2],0)/255:1)},D:function(a){this.c=this.b[a]||(this.b[a]=new L)},F:function(){},f:function(a){this.c.f(a)},g:function(a,b,c){this.c.g(a,b,c)},finish:function(){for(var a in this.b)this.h.c(a,this.b[a].j)}};M.prototype={f:function(a,b){var c=b?-2:2,d=this.c,f=[];for(b=b?a.length-2:0;b<a.length&&0<=b;b+=c)f.push(d.l(a[b],a[b+1]));this.h.f(f)},
|
||||
g:function(a,b,c,d){this.h.g(this.c.l(a,b,c,c),c,d)},a:function(a,b,c,d,f){this.f([a,b,a+c,b,a+c,b+d,a,b+d],f)},b:function(a,b,c,d,f,e){a=[a+c,b,a+c,b+d,a,b+d,a,b];a.splice((f||0)%4*2,2);this.f(a,e)},l:function(a,b,c,d,f){this.f([a+c/2,b,a+c,b+d/2,a+c/2,b+d,a,b+d/2],f)}};w.prototype={l:function(a,b,c,d){var f=this.b+this.h,e=this.c+this.h;return 1===this.a?new B(f-b-(d||0),this.c+a):2===this.a?new B(f-a-(c||0),e-b-(d||0)):3===this.a?new B(this.b+b,e-a-(c||0)):new B(this.b+a,this.c+b)}};w.a=new w(0,
|
||||
0,0,0);n.drawIcon=function(a,b,c,d){if(!a)throw Error("No canvas specified.");a=new E(a,c);H(a,C(b)||D(b),0,0,c,d||0,J())};n.toSvg=function(a,b,c){var d=new K(b);H(new G(d),C(a)||D(a),0,0,b,c,J());return d.toString()};n.update=x;n.version="2.1.1";y&&(y.fn.jdenticon=function(a,b){this.each(function(c,d){x(d,a,b)});return this});"function"===typeof setTimeout&&setTimeout(Q,0);return n});
|
||||
// Jdenticon 2.1.1 | jdenticon.com | MIT licensed | (c) 2014-2018 Daniel Mester Pirttijärvi
|
||||
(function(q,y,z){var t=z(q,q.jQuery);"undefined"!==typeof module&&"exports"in module?module.exports=t:"function"===typeof define&&define.amd?define([],function(){return t}):q[y]=t})(this,"jdenticon",function(q,y){function z(a,b,c){for(var d=document.createElementNS("http://www.w3.org/2000/svg",b),f=2;f+1<arguments.length;f+=2)d.setAttribute(arguments[f],arguments[f+1]);a.appendChild(d)}function t(a){this.b=Math.min(Number(a.getAttribute("width"))||100,Number(a.getAttribute("height"))||100);for(this.a=
|
||||
a;a.firstChild;)a.removeChild(a.firstChild);a.setAttribute("viewBox","0 0 "+this.b+" "+this.b);a.setAttribute("preserveAspectRatio","xMidYMid meet")}function K(a){this.b=a;this.a='\x3csvg xmlns\x3d"http://www.w3.org/2000/svg" width\x3d"'+a+'" height\x3d"'+a+'" viewBox\x3d"0 0 '+a+" "+a+'" preserveAspectRatio\x3d"xMidYMid meet"\x3e'}function N(a){return function(a){for(var b=[],d=0;d<a.length;d++)for(var f=a[d],e=28;0<=e;e-=4)b.push((f>>>e&15).toString(16));return b.join("")}(function(a){for(var b=
|
||||
1732584193,d=4023233417,f=2562383102,e=271733878,h=3285377520,k=[b,d,f,e,h],g=0;g<a.length;g++){for(var u=a[g],l=16;80>l;l++){var A=u[l-3]^u[l-8]^u[l-14]^u[l-16];u[l]=A<<1|A>>>31}for(l=0;80>l;l++)A=(b<<5|b>>>27)+(20>l?(d&f^~d&e)+1518500249:40>l?(d^f^e)+1859775393:60>l?(d&f^d&e^f&e)+2400959708:(d^f^e)+3395469782)+h+u[l],h=e,e=f,f=d<<30|d>>>2,d=b,b=A|0;k[0]=b=k[0]+b|0;k[1]=d=k[1]+d|0;k[2]=f=k[2]+f|0;k[3]=e=k[3]+e|0;k[4]=h=k[4]+h|0}return k}(function(a){function b(a,b){for(var c=[],d=-1,e=0;e<b;e++)d=
|
||||
e/4|0,c[d]=(c[d]||0)+(f[a+e]<<8*(3-(e&3)));for(;16>++d;)c[d]=0;return c}var d=encodeURI(a),f=[];a=0;var e,h=[];for(e=0;e<d.length;e++){if("%"==d[e]){var k=r(d,e+1,2);e+=2}else k=d.charCodeAt(e);f[a++]=k}f[a++]=128;for(e=0;e+64<=a;e+=64)h.push(b(e,64));d=a-e;e=b(e,d);64<d+8&&(h.push(e),e=b(0,0));e[15]=8*a-8;h.push(e);return h}(a)))}function E(a,b){var c=a.canvas.width,d=a.canvas.height;a.save();this.b=a;b?this.a=b:(this.a=Math.min(c,d),a.translate((c-this.a)/2|0,(d-this.a)/2|0));a.clearRect(0,0,this.a,
|
||||
this.a)}function v(a){a|=0;return 0>a?"00":16>a?"0"+a.toString(16):256>a?a.toString(16):"ff"}function F(a,b,c){c=0>c?c+6:6<c?c-6:c;return v(255*(1>c?a+(b-a)*c:3>c?b:4>c?a+(b-a)*(4-c):a))}function O(a){"undefined"!=typeof MutationObserver&&(new MutationObserver(function(b){for(var c=0;c<b.length;c++){for(var d=b[c],f=d.addedNodes,e=0;f&&e<f.length;e++){var h=f[e];if(1==h.nodeType)if(g.w(h))a(h);else{h=h.querySelectorAll(g.A);for(var k=0;k<h.length;k++)a(h[k])}}"attributes"==d.type&&g.w(d.target)&&
|
||||
a(d.target)}})).observe(document.body,{childList:!0,attributes:!0,attributeFilter:[g.o,g.s,"width","height"],subtree:!0})}function r(a,b,c){return parseInt(a.substr(b,c),16)}function p(a){return(10*a+.5|0)/10}function L(){this.j=""}function G(a){this.b={};this.h=a;this.a=a.b}function M(a){this.h=a;this.c=w.a}function P(a,b){a=b.O(a);return[m.i(a,b.H,b.G(0)),m.i(a,b.v,b.u(.5)),m.i(a,b.H,b.G(1)),m.i(a,b.v,b.u(1)),m.i(a,b.v,b.u(0))]}function B(a,b){this.x=a;this.y=b}function w(a,b,c,d){this.b=a;this.c=
|
||||
b;this.h=c;this.a=d}function H(a,b,c,d,f,e,h){function k(e,f,k,h,g){h=h?r(b,h,1):0;f=f[r(b,k,1)%f.length];a.D(p[n[e]]);for(e=0;e<g.length;e++)m.c=new w(c+g[e][0]*l,d+g[e][1]*l,l,h++%4),f(m,l,e);a.F()}function g(a){if(0<=a.indexOf(q))for(var b=0;b<a.length;b++)if(0<=n.indexOf(a[b]))return!0}h.C&&a.m(h.C);e=.5+f*(void 0===e?.08:e)|0;f-=2*e;var m=new M(a),l=0|f/4;c+=0|e+f/2-2*l;d+=0|e+f/2-2*l;var p=P(r(b,-7)/268435455,h),n=[];for(f=0;3>f;f++){var q=r(b,8+f,1)%p.length;if(g([0,4])||g([2,3]))q=1;n.push(q)}k(0,
|
||||
I.I,2,3,[[1,0],[2,0],[2,3],[1,3],[0,1],[3,1],[3,2],[0,2]]);k(1,I.I,4,5,[[0,0],[3,0],[3,3],[0,3]]);k(2,I.M,1,null,[[1,1],[2,1],[2,2],[1,2]]);a.finish()}function J(){function a(a,b){var d=c[a];d&&1<d.length||(d=b);return function(a){a=d[0]+a*(d[1]-d[0]);return 0>a?0:1<a?1:a}}var b=n.config||q.jdenticon_config||{},c=b.lightness||{},d=b.saturation||{},f="color"in d?d.color:d;d=d.grayscale;return{O:function(a){var c=b.hues,d;c&&0<c.length&&(d=c[0|.999*a*c.length]);return"number"==typeof d?(d/360%1+1)%
|
||||
1:a},v:"number"==typeof f?f:.5,H:"number"==typeof d?d:0,u:a("color",[.4,.8]),G:a("grayscale",[.3,.9]),C:m.parse(b.backColor)}}function C(a){return/^[0-9a-f]{11,}$/i.test(a)&&a}function D(a){return N(null==a?"":""+a)}function x(a,b,c){if("string"===typeof a){if(g.J){a=document.querySelectorAll(a);for(var d=0;d<a.length;d++)x(a[d],b,c)}}else if(d=g.w(a))if(b=C(b)||null!=b&&D(b)||C(a.getAttribute(g.s))||a.hasAttribute(g.o)&&D(a.getAttribute(g.o)))a=d==g.B?new G(new t(a)):new E(a.getContext("2d")),H(a,
|
||||
b,0,0,a.a,c,J())}function n(){g.J&&x(g.A)}function Q(){var a=(n.config||q.jdenticon_config||{}).replaceMode;"never"!=a&&(n(),"observe"==a&&O(x))}t.prototype={m:function(a,b){b&&z(this.a,"rect","width","100%","height","100%","fill",a,"opacity",b)},c:function(a,b){z(this.a,"path","fill",a,"d",b)}};K.prototype={m:function(a,b){b&&(this.a+='\x3crect width\x3d"100%" height\x3d"100%" fill\x3d"'+a+'" opacity\x3d"'+b.toFixed(2)+'"/\x3e')},c:function(a,b){this.a+='\x3cpath fill\x3d"'+a+'" d\x3d"'+b+'"/\x3e'},
|
||||
toString:function(){return this.a+"\x3c/svg\x3e"}};var g={B:1,L:2,s:"data-jdenticon-hash",o:"data-jdenticon-value",J:"undefined"!==typeof document&&"querySelectorAll"in document,w:function(a){if(a){var b=a.tagName;if(/svg/i.test(b))return g.B;if(/canvas/i.test(b)&&"getContext"in a)return g.L}}};g.A="["+g.s+"],["+g.o+"]";E.prototype={m:function(a){var b=this.b,c=this.a;b.fillStyle=m.K(a);b.fillRect(0,0,c,c)},D:function(a){this.b.fillStyle=m.K(a);this.b.beginPath()},F:function(){this.b.fill()},f:function(a){var b=
|
||||
this.b,c;b.moveTo(a[0].x,a[0].y);for(c=1;c<a.length;c++)b.lineTo(a[c].x,a[c].y);b.closePath()},g:function(a,b,c){var d=this.b;b/=2;d.moveTo(a.x+b,a.y+b);d.arc(a.x+b,a.y+b,b,0,2*Math.PI,c);d.closePath()},finish:function(){this.b.restore()}};var m={P:function(a,b,c){return"#"+v(a)+v(b)+v(c)},parse:function(a){if(/^#[0-9a-f]{3,8}$/i.test(a)){if(6>a.length){var b=a[1],c=a[2],d=a[3];a=a[4]||"";return"#"+b+b+c+c+d+d+a+a}if(7==a.length||8<a.length)return a}},K:function(a){var b=r(a,7,2);return isNaN(b)?
|
||||
a:"rgba("+r(a,1,2)+","+r(a,3,2)+","+r(a,5,2)+","+(b/255).toFixed(2)+")"},N:function(a,b,c){if(0==b)return a=v(255*c),"#"+a+a+a;b=.5>=c?c*(b+1):c+b-c*b;c=2*c-b;return"#"+F(c,b,6*a+2)+F(c,b,6*a)+F(c,b,6*a-2)},i:function(a,b,c){var d=[.55,.5,.5,.46,.6,.55,.55][6*a+.5|0];return m.N(a,b,.5>c?c*d*2:d+(c-.5)*(1-d)*2)}},I={M:[function(a,b){var c=.42*b;a.f([0,0,b,0,b,b-2*c,b-c,b,0,b])},function(a,b){var c=0|.5*b;a.b(b-c,0,c,0|.8*b,2)},function(a,b){var c=0|b/3;a.a(c,c,b-c,b-c)},function(a,b){var c=.1*b,d=
|
||||
6>b?1:8>b?2:0|.25*b;c=1<c?0|c:.5<c?1:c;a.a(d,d,b-c-d,b-c-d)},function(a,b){var c=0|.15*b,d=0|.5*b;a.g(b-d-c,b-d-c,d)},function(a,b){var c=.1*b,d=4*c;3<d&&(d|=0);a.a(0,0,b,b);a.f([d,d,b-c,d,d+(b-d-c)/2,b-c],!0)},function(a,b){a.f([0,0,b,0,b,.7*b,.4*b,.4*b,.7*b,b,0,b])},function(a,b){a.b(b/2,b/2,b/2,b/2,3)},function(a,b){a.a(0,0,b,b/2);a.a(0,b/2,b/2,b/2);a.b(b/2,b/2,b/2,b/2,1)},function(a,b){var c=.14*b,d=4>b?1:6>b?2:0|.35*b;c=8>b?c:0|c;a.a(0,0,b,b);a.a(d,d,b-d-c,b-d-c,!0)},function(a,b){var c=.12*
|
||||
b,d=3*c;a.a(0,0,b,b);a.g(d,d,b-c-d,!0)},function(a,b){a.b(b/2,b/2,b/2,b/2,3)},function(a,b){var c=.25*b;a.a(0,0,b,b);a.l(c,c,b-c,b-c,!0)},function(a,b,c){var d=.4*b;c||a.g(d,d,1.2*b)}],I:[function(a,b){a.b(0,0,b,b,0)},function(a,b){a.b(0,b/2,b,b/2,0)},function(a,b){a.l(0,0,b,b)},function(a,b){var c=b/6;a.g(c,c,b-2*c)}]};L.prototype={f:function(a){for(var b="M"+p(a[0].x)+" "+p(a[0].y),c=1;c<a.length;c++)b+="L"+p(a[c].x)+" "+p(a[c].y);this.j+=b+"Z"},g:function(a,b,c){c=c?0:1;var d=p(b/2),f=p(b);this.j+=
|
||||
"M"+p(a.x)+" "+p(a.y+b/2)+"a"+d+","+d+" 0 1,"+c+" "+f+",0a"+d+","+d+" 0 1,"+c+" "+-f+",0"}};G.prototype={m:function(a){a=/^(#......)(..)?/.exec(a);this.h.m(a[1],a[2]?r(a[2],0)/255:1)},D:function(a){this.c=this.b[a]||(this.b[a]=new L)},F:function(){},f:function(a){this.c.f(a)},g:function(a,b,c){this.c.g(a,b,c)},finish:function(){for(var a in this.b)this.h.c(a,this.b[a].j)}};M.prototype={f:function(a,b){var c=b?-2:2,d=this.c,f=[];for(b=b?a.length-2:0;b<a.length&&0<=b;b+=c)f.push(d.l(a[b],a[b+1]));this.h.f(f)},
|
||||
g:function(a,b,c,d){this.h.g(this.c.l(a,b,c,c),c,d)},a:function(a,b,c,d,f){this.f([a,b,a+c,b,a+c,b+d,a,b+d],f)},b:function(a,b,c,d,f,e){a=[a+c,b,a+c,b+d,a,b+d,a,b];a.splice((f||0)%4*2,2);this.f(a,e)},l:function(a,b,c,d,f){this.f([a+c/2,b,a+c,b+d/2,a+c/2,b+d,a,b+d/2],f)}};w.prototype={l:function(a,b,c,d){var f=this.b+this.h,e=this.c+this.h;return 1===this.a?new B(f-b-(d||0),this.c+a):2===this.a?new B(f-a-(c||0),e-b-(d||0)):3===this.a?new B(this.b+b,e-a-(c||0)):new B(this.b+a,this.c+b)}};w.a=new w(0,
|
||||
0,0,0);n.drawIcon=function(a,b,c,d){if(!a)throw Error("No canvas specified.");a=new E(a,c);H(a,C(b)||D(b),0,0,c,d||0,J())};n.toSvg=function(a,b,c){var d=new K(b);H(new G(d),C(a)||D(a),0,0,b,c,J());return d.toString()};n.update=x;n.version="2.1.1";y&&(y.fn.jdenticon=function(a,b){this.each(function(c,d){x(d,a,b)});return this});"function"===typeof setTimeout&&setTimeout(Q,0);return n});
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Types } from '@dotstats/common';
|
||||
import { Types } from './common';
|
||||
import { State, UpdateBound } from './state';
|
||||
|
||||
// Number of blocks which are kept in memory
|
||||
@@ -21,7 +21,7 @@ export class AfgHandling {
|
||||
this.getState().authoritySetId != null &&
|
||||
authoritySetId !== this.getState().authoritySetId
|
||||
) {
|
||||
// the visualization is restarted when we receive a new auhority set
|
||||
// the visualization is restarted when we receive a new authority set
|
||||
this.updateState({
|
||||
authoritySetId,
|
||||
authorities,
|
||||
@@ -113,7 +113,6 @@ export class AfgHandling {
|
||||
public receivedPre(
|
||||
addr: Types.Address,
|
||||
height: Types.BlockNumber,
|
||||
hash: Types.BlockHash,
|
||||
voter: Types.Address,
|
||||
what: string
|
||||
) {
|
||||
@@ -136,7 +135,7 @@ export class AfgHandling {
|
||||
// a vote on all preceding blocks. This function marks
|
||||
// the preceding blocks as implicitly voted on and stores
|
||||
// a pointer to the block which contains the explicit vote.
|
||||
const op = (i: Types.BlockNumber, index: number): boolean => {
|
||||
const op = (index: number): boolean => {
|
||||
const consensusDetail = state.consensusInfo[index][1][addr][voter];
|
||||
if (
|
||||
what === 'prevote' &&
|
||||
@@ -192,7 +191,7 @@ export class AfgHandling {
|
||||
|
||||
const item: Types.ConsensusItem = [height, consensusView];
|
||||
const insertPos = consensusInfo.findIndex(
|
||||
([elHeight, elView]) => elHeight < height
|
||||
([elHeight]) => elHeight < height
|
||||
);
|
||||
if (insertPos >= 0) {
|
||||
consensusInfo.splice(insertPos, 0, item);
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
.App-no-telemetry {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
line-height: 80vh;
|
||||
/* height: 100vh; */
|
||||
/* line-height: 80vh; */
|
||||
font-size: 56px;
|
||||
font-weight: 100;
|
||||
text-align: center;
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, SortedCollection, Maybe, Compare } from '@dotstats/common';
|
||||
import { Types, SortedCollection, Maybe, Compare } from './common';
|
||||
import { AllChains, Chains, Chain, Ago, OfflineIndicator } from './components';
|
||||
import { Row, Column } from './components/List';
|
||||
import { Connection } from './Connection';
|
||||
@@ -189,7 +189,7 @@ export default class App extends React.Component<{}, State> {
|
||||
});
|
||||
};
|
||||
|
||||
private onHashChange = (event: Event) => {
|
||||
private onHashChange = () => {
|
||||
const { tab = '' } = getHashData();
|
||||
|
||||
this.setState({ tab });
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
VERSION,
|
||||
timestamp,
|
||||
FeedMessage,
|
||||
Types,
|
||||
Maybe,
|
||||
sleep,
|
||||
} from '@dotstats/common';
|
||||
import { VERSION, timestamp, FeedMessage, Types, Maybe, sleep } from './common';
|
||||
import {
|
||||
State,
|
||||
Update,
|
||||
@@ -17,10 +10,9 @@ import {
|
||||
import { PersistentSet } from './persist';
|
||||
import { getHashData, setHashData } from './utils';
|
||||
import { AfgHandling } from './AfgHandling';
|
||||
import { VIS_AUTHORITIES_LIMIT } from '../../frontend/src/components/Consensus';
|
||||
import { VIS_AUTHORITIES_LIMIT } from './components/Consensus';
|
||||
import { Column } from './components/List';
|
||||
|
||||
const { Actions } = FeedMessage;
|
||||
import { ACTIONS } from './common/feed';
|
||||
|
||||
const TIMEOUT_BASE = (1000 * 5) as Types.Milliseconds; // 5 seconds
|
||||
const TIMEOUT_MAX = (1000 * 60 * 5) as Types.Milliseconds; // 5 minutes
|
||||
@@ -40,8 +32,6 @@ export class Connection {
|
||||
? `wss://${window.location.hostname}/feed/`
|
||||
: `ws://127.0.0.1:8000/feed`;
|
||||
|
||||
// private static readonly address = 'wss://telemetry.polkadot.io/feed/';
|
||||
|
||||
private static async socket(): Promise<WebSocket> {
|
||||
let socket = await Connection.trySocket();
|
||||
let timeout = TIMEOUT_BASE;
|
||||
@@ -158,7 +148,7 @@ export class Connection {
|
||||
|
||||
for (const message of messages) {
|
||||
switch (message.action) {
|
||||
case Actions.FeedVersion: {
|
||||
case ACTIONS.FeedVersion: {
|
||||
if (message.payload !== VERSION) {
|
||||
this.state = this.update({ status: 'upgrade-requested' });
|
||||
this.clean();
|
||||
@@ -172,7 +162,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.BestBlock: {
|
||||
case ACTIONS.BestBlock: {
|
||||
const [best, blockTimestamp, blockAverage] = message.payload;
|
||||
|
||||
nodes.mutEach((node) => node.newBestBlock());
|
||||
@@ -182,7 +172,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.BestFinalized: {
|
||||
case ACTIONS.BestFinalized: {
|
||||
const [finalized /*, hash */] = message.payload;
|
||||
|
||||
this.state = this.update({ finalized });
|
||||
@@ -190,7 +180,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.AddedNode: {
|
||||
case ACTIONS.AddedNode: {
|
||||
const [
|
||||
id,
|
||||
nodeDetails,
|
||||
@@ -219,7 +209,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.RemovedNode: {
|
||||
case ACTIONS.RemovedNode: {
|
||||
const id = message.payload;
|
||||
|
||||
nodes.remove(id);
|
||||
@@ -227,7 +217,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.StaleNode: {
|
||||
case ACTIONS.StaleNode: {
|
||||
const id = message.payload;
|
||||
|
||||
nodes.mutAndSort(id, (node) => node.setStale(true));
|
||||
@@ -235,7 +225,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.LocatedNode: {
|
||||
case ACTIONS.LocatedNode: {
|
||||
const [id, lat, lon, city] = message.payload;
|
||||
|
||||
nodes.mutAndMaybeSort(
|
||||
@@ -247,7 +237,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.ImportedBlock: {
|
||||
case ACTIONS.ImportedBlock: {
|
||||
const [id, blockDetails] = message.payload;
|
||||
|
||||
nodes.mutAndSort(id, (node) => node.updateBlock(blockDetails));
|
||||
@@ -255,7 +245,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.FinalizedBlock: {
|
||||
case ACTIONS.FinalizedBlock: {
|
||||
const [id, height, hash] = message.payload;
|
||||
|
||||
nodes.mutAndMaybeSort(
|
||||
@@ -268,7 +258,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.NodeStats: {
|
||||
case ACTIONS.NodeStats: {
|
||||
const [id, nodeStats] = message.payload;
|
||||
|
||||
nodes.mutAndMaybeSort(
|
||||
@@ -280,7 +270,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.NodeHardware: {
|
||||
case ACTIONS.NodeHardware: {
|
||||
const [id, nodeHardware] = message.payload;
|
||||
|
||||
nodes.mutAndMaybeSort(
|
||||
@@ -295,7 +285,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.NodeIO: {
|
||||
case ACTIONS.NodeIO: {
|
||||
const [id, nodeIO] = message.payload;
|
||||
|
||||
nodes.mutAndMaybeSort(
|
||||
@@ -310,7 +300,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.TimeSync: {
|
||||
case ACTIONS.TimeSync: {
|
||||
this.state = this.update({
|
||||
timeDiff: (timestamp() - message.payload) as Types.Milliseconds,
|
||||
});
|
||||
@@ -318,7 +308,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.AddedChain: {
|
||||
case ACTIONS.AddedChain: {
|
||||
const [label, nodeCount] = message.payload;
|
||||
const chain = chains.get(label);
|
||||
|
||||
@@ -333,7 +323,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.RemovedChain: {
|
||||
case ACTIONS.RemovedChain: {
|
||||
chains.delete(message.payload);
|
||||
|
||||
if (this.state.subscribed === message.payload) {
|
||||
@@ -345,7 +335,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.SubscribedTo: {
|
||||
case ACTIONS.SubscribedTo: {
|
||||
nodes.clear();
|
||||
|
||||
this.state = this.update({ subscribed: message.payload, nodes });
|
||||
@@ -353,7 +343,7 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.UnsubscribedFrom: {
|
||||
case ACTIONS.UnsubscribedFrom: {
|
||||
if (this.state.subscribed === message.payload) {
|
||||
nodes.clear();
|
||||
|
||||
@@ -363,13 +353,13 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.Pong: {
|
||||
case ACTIONS.Pong: {
|
||||
this.pong(Number(message.payload));
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.AfgFinalized: {
|
||||
case ACTIONS.AfgFinalized: {
|
||||
const [nodeAddress, finalizedNumber, finalizedHash] = message.payload;
|
||||
const no = parseInt(String(finalizedNumber), 10) as Types.BlockNumber;
|
||||
afg.receivedFinalized(nodeAddress, no, finalizedHash);
|
||||
@@ -377,23 +367,23 @@ export class Connection {
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.AfgReceivedPrevote: {
|
||||
case ACTIONS.AfgReceivedPrevote: {
|
||||
const [nodeAddress, blockNumber, blockHash, voter] = message.payload;
|
||||
const no = parseInt(String(blockNumber), 10) as Types.BlockNumber;
|
||||
afg.receivedPre(nodeAddress, no, blockHash, voter, 'prevote');
|
||||
afg.receivedPre(nodeAddress, no, voter, 'prevote');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.AfgReceivedPrecommit: {
|
||||
case ACTIONS.AfgReceivedPrecommit: {
|
||||
const [nodeAddress, blockNumber, blockHash, voter] = message.payload;
|
||||
const no = parseInt(String(blockNumber), 10) as Types.BlockNumber;
|
||||
afg.receivedPre(nodeAddress, no, blockHash, voter, 'precommit');
|
||||
afg.receivedPre(nodeAddress, no, voter, 'precommit');
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case Actions.AfgAuthoritySet: {
|
||||
case ACTIONS.AfgAuthoritySet: {
|
||||
const [authoritySetId, authorities] = message.payload;
|
||||
afg.receivedAuthoritySet(authoritySetId, authorities);
|
||||
|
||||
|
Before Width: | Height: | Size: 324 KiB After Width: | Height: | Size: 324 KiB |
@@ -12,7 +12,11 @@ export type Compare<T> = (a: T, b: T) => number;
|
||||
*
|
||||
* @return {number} insertion index
|
||||
*/
|
||||
export function sortedInsert<T>(item: T, into: Array<T>, compare: Compare<T>): number {
|
||||
export function sortedInsert<T>(
|
||||
item: T,
|
||||
into: Array<T>,
|
||||
compare: Compare<T>
|
||||
): number {
|
||||
if (into.length === 0) {
|
||||
into.push(item);
|
||||
|
||||
@@ -23,7 +27,7 @@ export function sortedInsert<T>(item: T, into: Array<T>, compare: Compare<T>): n
|
||||
let max = into.length - 1;
|
||||
|
||||
while (min !== max) {
|
||||
const guess = (min + max) / 2 | 0;
|
||||
const guess = ((min + max) / 2) | 0;
|
||||
|
||||
if (compare(item, into[guess]) < 0) {
|
||||
max = Math.max(min, guess - 1);
|
||||
@@ -50,7 +54,11 @@ export function sortedInsert<T>(item: T, into: Array<T>, compare: Compare<T>): n
|
||||
*
|
||||
* @return {number} index of the element, `-1` if not found
|
||||
*/
|
||||
export function sortedIndexOf<T>(item: T, within: Array<T>, compare: Compare<T>): number {
|
||||
export function sortedIndexOf<T>(
|
||||
item: T,
|
||||
within: Array<T>,
|
||||
compare: Compare<T>
|
||||
): number {
|
||||
if (within.length === 0) {
|
||||
return -1;
|
||||
}
|
||||
@@ -59,7 +67,7 @@ export function sortedIndexOf<T>(item: T, within: Array<T>, compare: Compare<T>)
|
||||
let max = within.length - 1;
|
||||
|
||||
while (min !== max) {
|
||||
let guess = (min + max) / 2 | 0;
|
||||
const guess = ((min + max) / 2) | 0;
|
||||
const other = within[guess];
|
||||
|
||||
if (item === other) {
|
||||
@@ -113,7 +121,9 @@ export class SortedCollection<Item extends { id: number }> {
|
||||
public add(item: Item) {
|
||||
if (this.map.length <= item.id) {
|
||||
// Grow map if item.id would be out of scope
|
||||
this.map = this.map.concat(Array<Maybe<Item>>(Math.max(10, 1 + item.id - this.map.length)));
|
||||
this.map = this.map.concat(
|
||||
Array<Maybe<Item>>(Math.max(10, 1 + item.id - this.map.length))
|
||||
);
|
||||
}
|
||||
|
||||
// Remove old item if overriding
|
||||
@@ -178,7 +188,11 @@ export class SortedCollection<Item extends { id: number }> {
|
||||
}
|
||||
}
|
||||
|
||||
public mutAndMaybeSort(id: number, mutator: (item: Item) => void, sort: boolean) {
|
||||
public mutAndMaybeSort(
|
||||
id: number,
|
||||
mutator: (item: Item) => void,
|
||||
sort: boolean
|
||||
) {
|
||||
if (sort) {
|
||||
this.mutAndSort(id, mutator);
|
||||
} else {
|
||||
@@ -1,4 +1,4 @@
|
||||
import { Opaque, Maybe } from './helpers';
|
||||
import { Maybe } from './helpers';
|
||||
import { stringify, parse, Stringified } from './stringify';
|
||||
import {
|
||||
FeedVersion,
|
||||
@@ -22,32 +22,32 @@ import {
|
||||
AuthoritySetInfo,
|
||||
} from './types';
|
||||
|
||||
export const Actions = {
|
||||
FeedVersion : 0x00 as 0x00,
|
||||
BestBlock : 0x01 as 0x01,
|
||||
BestFinalized : 0x02 as 0x02,
|
||||
AddedNode : 0x03 as 0x03,
|
||||
RemovedNode : 0x04 as 0x04,
|
||||
LocatedNode : 0x05 as 0x05,
|
||||
ImportedBlock : 0x06 as 0x06,
|
||||
FinalizedBlock : 0x07 as 0x07,
|
||||
NodeStats : 0x08 as 0x08,
|
||||
NodeHardware : 0x09 as 0x09,
|
||||
TimeSync : 0x0A as 0x0A,
|
||||
AddedChain : 0x0B as 0x0B,
|
||||
RemovedChain : 0x0C as 0x0C,
|
||||
SubscribedTo : 0x0D as 0x0D,
|
||||
UnsubscribedFrom : 0x0E as 0x0E,
|
||||
Pong : 0x0F as 0x0F,
|
||||
AfgFinalized : 0x10 as 0x10,
|
||||
AfgReceivedPrevote : 0x11 as 0x11,
|
||||
AfgReceivedPrecommit : 0x12 as 0x12,
|
||||
AfgAuthoritySet : 0x13 as 0x13,
|
||||
StaleNode : 0x14 as 0x14,
|
||||
NodeIO : 0x15 as 0x15,
|
||||
export const ACTIONS = {
|
||||
FeedVersion: 0x00 as 0x00,
|
||||
BestBlock: 0x01 as 0x01,
|
||||
BestFinalized: 0x02 as 0x02,
|
||||
AddedNode: 0x03 as 0x03,
|
||||
RemovedNode: 0x04 as 0x04,
|
||||
LocatedNode: 0x05 as 0x05,
|
||||
ImportedBlock: 0x06 as 0x06,
|
||||
FinalizedBlock: 0x07 as 0x07,
|
||||
NodeStats: 0x08 as 0x08,
|
||||
NodeHardware: 0x09 as 0x09,
|
||||
TimeSync: 0x0a as 0x0a,
|
||||
AddedChain: 0x0b as 0x0b,
|
||||
RemovedChain: 0x0c as 0x0c,
|
||||
SubscribedTo: 0x0d as 0x0d,
|
||||
UnsubscribedFrom: 0x0e as 0x0e,
|
||||
Pong: 0x0f as 0x0f,
|
||||
AfgFinalized: 0x10 as 0x10,
|
||||
AfgReceivedPrevote: 0x11 as 0x11,
|
||||
AfgReceivedPrecommit: 0x12 as 0x12,
|
||||
AfgAuthoritySet: 0x13 as 0x13,
|
||||
StaleNode: 0x14 as 0x14,
|
||||
NodeIO: 0x15 as 0x15,
|
||||
};
|
||||
|
||||
export type Action = typeof Actions[keyof typeof Actions];
|
||||
export type Action = typeof ACTIONS[keyof typeof ACTIONS];
|
||||
export type Payload = Message['payload'];
|
||||
|
||||
export namespace Variants {
|
||||
@@ -56,112 +56,121 @@ export namespace Variants {
|
||||
}
|
||||
|
||||
export interface FeedVersionMessage extends MessageBase {
|
||||
action: typeof Actions.FeedVersion;
|
||||
action: typeof ACTIONS.FeedVersion;
|
||||
payload: FeedVersion;
|
||||
}
|
||||
|
||||
export interface BestBlockMessage extends MessageBase {
|
||||
action: typeof Actions.BestBlock;
|
||||
action: typeof ACTIONS.BestBlock;
|
||||
payload: [BlockNumber, Timestamp, Maybe<Milliseconds>];
|
||||
}
|
||||
|
||||
export interface BestFinalizedBlockMessage extends MessageBase {
|
||||
action: typeof Actions.BestFinalized;
|
||||
action: typeof ACTIONS.BestFinalized;
|
||||
payload: [BlockNumber, BlockHash];
|
||||
}
|
||||
|
||||
export interface AddedNodeMessage extends MessageBase {
|
||||
action: typeof Actions.AddedNode;
|
||||
payload: [NodeId, NodeDetails, NodeStats, NodeIO, NodeHardware, BlockDetails, Maybe<NodeLocation>, Timestamp];
|
||||
action: typeof ACTIONS.AddedNode;
|
||||
payload: [
|
||||
NodeId,
|
||||
NodeDetails,
|
||||
NodeStats,
|
||||
NodeIO,
|
||||
NodeHardware,
|
||||
BlockDetails,
|
||||
Maybe<NodeLocation>,
|
||||
Timestamp
|
||||
];
|
||||
}
|
||||
|
||||
export interface RemovedNodeMessage extends MessageBase {
|
||||
action: typeof Actions.RemovedNode;
|
||||
action: typeof ACTIONS.RemovedNode;
|
||||
payload: NodeId;
|
||||
}
|
||||
|
||||
export interface LocatedNodeMessage extends MessageBase {
|
||||
action: typeof Actions.LocatedNode;
|
||||
action: typeof ACTIONS.LocatedNode;
|
||||
payload: [NodeId, Latitude, Longitude, City];
|
||||
}
|
||||
|
||||
export interface ImportedBlockMessage extends MessageBase {
|
||||
action: typeof Actions.ImportedBlock;
|
||||
action: typeof ACTIONS.ImportedBlock;
|
||||
payload: [NodeId, BlockDetails];
|
||||
}
|
||||
|
||||
export interface FinalizedBlockMessage extends MessageBase {
|
||||
action: typeof Actions.FinalizedBlock;
|
||||
action: typeof ACTIONS.FinalizedBlock;
|
||||
payload: [NodeId, BlockNumber, BlockHash];
|
||||
}
|
||||
|
||||
export interface NodeStatsMessage extends MessageBase {
|
||||
action: typeof Actions.NodeStats;
|
||||
action: typeof ACTIONS.NodeStats;
|
||||
payload: [NodeId, NodeStats];
|
||||
}
|
||||
|
||||
export interface NodeHardwareMessage extends MessageBase {
|
||||
action: typeof Actions.NodeHardware;
|
||||
action: typeof ACTIONS.NodeHardware;
|
||||
payload: [NodeId, NodeHardware];
|
||||
}
|
||||
|
||||
export interface NodeIOMessage extends MessageBase {
|
||||
action: typeof Actions.NodeIO;
|
||||
action: typeof ACTIONS.NodeIO;
|
||||
payload: [NodeId, NodeIO];
|
||||
}
|
||||
|
||||
export interface TimeSyncMessage extends MessageBase {
|
||||
action: typeof Actions.TimeSync;
|
||||
action: typeof ACTIONS.TimeSync;
|
||||
payload: Timestamp;
|
||||
}
|
||||
|
||||
export interface AddedChainMessage extends MessageBase {
|
||||
action: typeof Actions.AddedChain;
|
||||
action: typeof ACTIONS.AddedChain;
|
||||
payload: [ChainLabel, NodeCount];
|
||||
}
|
||||
|
||||
export interface RemovedChainMessage extends MessageBase {
|
||||
action: typeof Actions.RemovedChain;
|
||||
action: typeof ACTIONS.RemovedChain;
|
||||
payload: ChainLabel;
|
||||
}
|
||||
|
||||
export interface SubscribedToMessage extends MessageBase {
|
||||
action: typeof Actions.SubscribedTo;
|
||||
action: typeof ACTIONS.SubscribedTo;
|
||||
payload: ChainLabel;
|
||||
}
|
||||
|
||||
export interface UnsubscribedFromMessage extends MessageBase {
|
||||
action: typeof Actions.UnsubscribedFrom;
|
||||
action: typeof ACTIONS.UnsubscribedFrom;
|
||||
payload: ChainLabel;
|
||||
}
|
||||
|
||||
export interface PongMessage extends MessageBase {
|
||||
action: typeof Actions.Pong;
|
||||
action: typeof ACTIONS.Pong;
|
||||
payload: string; // just echo whatever `ping` sent
|
||||
}
|
||||
|
||||
export interface AfgFinalizedMessage extends MessageBase {
|
||||
action: typeof Actions.AfgFinalized;
|
||||
action: typeof ACTIONS.AfgFinalized;
|
||||
payload: [Address, BlockNumber, BlockHash];
|
||||
}
|
||||
|
||||
export interface AfgAuthoritySet extends MessageBase {
|
||||
action: typeof Actions.AfgAuthoritySet;
|
||||
action: typeof ACTIONS.AfgAuthoritySet;
|
||||
payload: AuthoritySetInfo;
|
||||
}
|
||||
|
||||
export interface AfgReceivedPrecommit extends MessageBase {
|
||||
action: typeof Actions.AfgReceivedPrecommit;
|
||||
action: typeof ACTIONS.AfgReceivedPrecommit;
|
||||
payload: [Address, BlockNumber, BlockHash, Address];
|
||||
}
|
||||
|
||||
export interface AfgReceivedPrevote extends MessageBase {
|
||||
action: typeof Actions.AfgReceivedPrevote;
|
||||
action: typeof ACTIONS.AfgReceivedPrevote;
|
||||
payload: [Address, BlockNumber, BlockHash, Address];
|
||||
}
|
||||
|
||||
export interface StaleNodeMessage extends MessageBase {
|
||||
action: typeof Actions.StaleNode;
|
||||
action: typeof ACTIONS.StaleNode;
|
||||
payload: NodeId;
|
||||
}
|
||||
}
|
||||
@@ -194,7 +203,7 @@ export type Message =
|
||||
* Data type to be sent to the feed. Passing through strings means we can only serialize once,
|
||||
* no matter how many feed clients are listening in.
|
||||
*/
|
||||
export interface SquashedMessages extends Array<Action | Payload> {};
|
||||
export interface SquashedMessages extends Array<Action | Payload> {}
|
||||
export type Data = Stringified<SquashedMessages>;
|
||||
|
||||
/**
|
||||
@@ -213,7 +222,7 @@ export function serialize(messages: Array<Message>): Data {
|
||||
|
||||
squashed[index++] = action;
|
||||
squashed[index++] = payload;
|
||||
})
|
||||
});
|
||||
|
||||
return stringify(squashed);
|
||||
}
|
||||
@@ -231,7 +240,7 @@ export function deserialize(data: Data): Array<Message> {
|
||||
const messages = new Array<Message>(json.length / 2);
|
||||
|
||||
for (const index of messages.keys()) {
|
||||
const [ action, payload ] = json.slice(index * 2);
|
||||
const [action, payload] = json.slice(index * 2);
|
||||
|
||||
messages[index] = { action, payload } as Message;
|
||||
}
|
||||
@@ -4,7 +4,9 @@ import { Milliseconds, Timestamp } from './types';
|
||||
* PhantomData akin to Rust, because sometimes you need to be smarter than
|
||||
* the compiler.
|
||||
*/
|
||||
export abstract class PhantomData<P> { public __PHANTOM__: P }
|
||||
export abstract class PhantomData<P> {
|
||||
public __PHANTOM__: P;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opaque type, similar to `opaque type` in Flow, or new types in Rust/C.
|
||||
@@ -109,6 +111,8 @@ export class NumStats<T extends number> {
|
||||
}
|
||||
|
||||
private nonEmpty(): Readonly<Array<number>> {
|
||||
return this.index < this.history ? this.stack.slice(0, this.index) : this.stack;
|
||||
return this.index < this.history
|
||||
? this.stack.slice(0, this.index)
|
||||
: this.stack;
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export type Id<T> = Opaque<number, T>;
|
||||
* Higher order function producing new auto-incremented `Id`s.
|
||||
*/
|
||||
export function idGenerator<I extends Id<any>>(): () => I {
|
||||
let current = 0;
|
||||
let current = 0;
|
||||
|
||||
return () => current++ as I;
|
||||
return () => current++ as I;
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
export function* map<T, U>(
|
||||
iter: IterableIterator<T>,
|
||||
fn: (item: T) => U
|
||||
): IterableIterator<U> {
|
||||
for (const item of iter) {
|
||||
yield fn(item);
|
||||
}
|
||||
}
|
||||
|
||||
export function* chain<T>(
|
||||
a: IterableIterator<T>,
|
||||
b: IterableIterator<T>
|
||||
): IterableIterator<T> {
|
||||
yield* a;
|
||||
yield* b;
|
||||
}
|
||||
|
||||
export function* zip<T, U>(
|
||||
a: IterableIterator<T>,
|
||||
b: IterableIterator<U>
|
||||
): IterableIterator<[T, U]> {
|
||||
let itemA = a.next();
|
||||
let itemB = b.next();
|
||||
|
||||
while (!itemA.done && !itemB.done) {
|
||||
yield [itemA.value, itemB.value];
|
||||
|
||||
itemA = a.next();
|
||||
itemB = b.next();
|
||||
}
|
||||
}
|
||||
|
||||
export function* take<T>(
|
||||
iter: IterableIterator<T>,
|
||||
n: number
|
||||
): IterableIterator<T> {
|
||||
for (const item of iter) {
|
||||
if (n-- === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
yield item;
|
||||
}
|
||||
}
|
||||
|
||||
export function skip<T>(
|
||||
iter: IterableIterator<T>,
|
||||
n: number
|
||||
): IterableIterator<T> {
|
||||
while (n-- !== 0 && !iter.next().done) {}
|
||||
|
||||
return iter;
|
||||
}
|
||||
|
||||
export function reduce<T, R>(
|
||||
iter: IterableIterator<T>,
|
||||
fn: (accu: R, item: T) => R,
|
||||
accumulator: R
|
||||
): R {
|
||||
for (const item of iter) {
|
||||
accumulator = fn(accumulator, item);
|
||||
}
|
||||
|
||||
return accumulator;
|
||||
}
|
||||
|
||||
export function join(
|
||||
iter: IterableIterator<{ toString: () => string }>,
|
||||
glue: string
|
||||
): string {
|
||||
const first = iter.next();
|
||||
|
||||
if (first.done) {
|
||||
return '';
|
||||
}
|
||||
|
||||
let result = first.value.toString();
|
||||
|
||||
for (const item of iter) {
|
||||
result += glue + item;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
export abstract class Stringified<T> {
|
||||
public __PHANTOM__: T;
|
||||
}
|
||||
|
||||
export const parse = (JSON.parse as any) as <T>(val: Stringified<T>) => T;
|
||||
export const stringify = (JSON.stringify as any) as <T>(
|
||||
val: T
|
||||
) => Stringified<T>;
|
||||
@@ -27,26 +27,55 @@ export type BytesPerSecond = Opaque<number, 'BytesPerSecond'>;
|
||||
export type NetworkId = Opaque<string, 'NetworkId'>;
|
||||
export type NetworkState = Opaque<string | object, 'NetworkState'>;
|
||||
|
||||
export type BlockDetails = [BlockNumber, BlockHash, Milliseconds, Timestamp, Maybe<PropagationTime>];
|
||||
export type NodeDetails = [NodeName, NodeImplementation, NodeVersion, Maybe<Address>, Maybe<NetworkId>];
|
||||
export type BlockDetails = [
|
||||
BlockNumber,
|
||||
BlockHash,
|
||||
Milliseconds,
|
||||
Timestamp,
|
||||
Maybe<PropagationTime>
|
||||
];
|
||||
export type NodeDetails = [
|
||||
NodeName,
|
||||
NodeImplementation,
|
||||
NodeVersion,
|
||||
Maybe<Address>,
|
||||
Maybe<NetworkId>
|
||||
];
|
||||
export type NodeStats = [PeerCount, TransactionCount];
|
||||
export type NodeIO = [Array<Bytes>, Array<Bytes>, Array<BytesPerSecond>, Array<BytesPerSecond>];
|
||||
export type NodeHardware = [Array<MemoryUse>, Array<CPUUse>, Array<BytesPerSecond>, Array<BytesPerSecond>, Array<Timestamp>];
|
||||
export type NodeIO = [
|
||||
Array<Bytes>,
|
||||
Array<Bytes>,
|
||||
Array<BytesPerSecond>,
|
||||
Array<BytesPerSecond>
|
||||
];
|
||||
export type NodeHardware = [
|
||||
Array<MemoryUse>,
|
||||
Array<CPUUse>,
|
||||
Array<BytesPerSecond>,
|
||||
Array<BytesPerSecond>,
|
||||
Array<Timestamp>
|
||||
];
|
||||
export type NodeLocation = [Latitude, Longitude, City];
|
||||
|
||||
export declare type Authority = {
|
||||
Address: Address,
|
||||
NodeId: Maybe<NodeId>,
|
||||
Name: Maybe<NodeName>,
|
||||
};
|
||||
export interface Authority {
|
||||
Address: Address;
|
||||
NodeId: Maybe<NodeId>;
|
||||
Name: Maybe<NodeName>;
|
||||
}
|
||||
export declare type Authorities = Array<Address>;
|
||||
export declare type AuthoritySetId = Opaque<number, 'AuthoritySetId'>;
|
||||
export declare type AuthoritySetInfo = [AuthoritySetId, Authorities, Address, BlockNumber, BlockHash];
|
||||
export declare type AuthoritySetInfo = [
|
||||
AuthoritySetId,
|
||||
Authorities,
|
||||
Address,
|
||||
BlockNumber,
|
||||
BlockHash
|
||||
];
|
||||
export declare type ConsensusItem = [BlockNumber, ConsensusView];
|
||||
export declare type ConsensusInfo = Array<ConsensusItem>;
|
||||
export declare type ConsensusView = Map<Address, ConsensusState>;
|
||||
export declare type ConsensusState = Map<Address, ConsensusDetail>;
|
||||
export declare type ConsensusDetail = {
|
||||
export interface ConsensusDetail {
|
||||
Precommit: Precommit;
|
||||
ImplicitPrecommit: ImplicitPrecommit;
|
||||
Prevote: Prevote;
|
||||
@@ -56,7 +85,7 @@ export declare type ConsensusDetail = {
|
||||
ImplicitFinalized: Finalized;
|
||||
FinalizedHash: BlockHash;
|
||||
FinalizedHeight: BlockNumber;
|
||||
};
|
||||
}
|
||||
export declare type Precommit = Opaque<boolean, 'Precommit'>;
|
||||
export declare type Prevote = Opaque<boolean, 'Prevote'>;
|
||||
export declare type Finalized = Opaque<boolean, 'Finalized'>;
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import './Tile.css';
|
||||
import { timestamp, Types } from '@dotstats/common';
|
||||
import { timestamp, Types } from '../common';
|
||||
|
||||
export namespace Ago {
|
||||
export interface Props {
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { Connection } from '../Connection';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../common';
|
||||
import { ChainData } from '../state';
|
||||
|
||||
import './AllChains.css';
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as React from 'react';
|
||||
import { Connection } from '../../Connection';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../../common';
|
||||
import { State as AppState } from '../../state';
|
||||
import { formatNumber, secondsWithPrecision, getHashData } from '../../utils';
|
||||
import { Tab } from './';
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
import { Connection } from '../Connection';
|
||||
import { Icon } from './Icon';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../common';
|
||||
import { ChainData } from '../state';
|
||||
|
||||
import githubIcon from '../icons/mark-github.svg';
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../../common';
|
||||
import { Connection } from '../../Connection';
|
||||
import Measure, { BoundingRect, ContentRect } from 'react-measure';
|
||||
|
||||
@@ -357,7 +357,7 @@ export class Consensus extends React.Component<Consensus.Props, {}> {
|
||||
|
||||
private getSmallRow(blocks: Types.ConsensusInfo) {
|
||||
const smallBlockSizeChanged = (
|
||||
isFirstBlock: boolean,
|
||||
_isFirstBlock: boolean,
|
||||
rect: BoundingRect
|
||||
) => {
|
||||
if (this.smallBlocksSizeDetected(this.state)) {
|
||||
@@ -1,7 +1,7 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import Measure, { BoundingRect, ContentRect } from 'react-measure';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../../common';
|
||||
|
||||
import { Icon, Tooltip, PolkadotIcon } from '../';
|
||||
import Jdenticon from './Jdenticon';
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Maybe } from '@dotstats/common';
|
||||
import { Maybe } from '../common';
|
||||
import { Node } from '../state';
|
||||
import { Icon } from './';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, Maybe, timestamp } from '@dotstats/common';
|
||||
import { Types, Maybe, timestamp } from '../../common';
|
||||
import { State, Node } from '../../state';
|
||||
import { Truncate } from './';
|
||||
import { Ago, Icon, Tooltip, Sparkline, PolkadotIcon } from '../';
|
||||
@@ -59,6 +59,7 @@ import dothereumIcon from '../../icons/dothereum.svg';
|
||||
import katalchainIcon from '../../icons/katalchain.svg';
|
||||
import bifrostIcon from '../../icons/bifrost.svg';
|
||||
import totemIcon from '../../icons/totem.svg';
|
||||
|
||||
import unknownImplementationIcon from '../../icons/question-solid.svg';
|
||||
|
||||
const ICONS = {
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Maybe } from '@dotstats/common';
|
||||
import { Maybe } from '../../common';
|
||||
import { Column } from './';
|
||||
import { Icon, Tooltip } from '../';
|
||||
import { Persistent } from '../../persist';
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../../common';
|
||||
import { Filter } from '../';
|
||||
import { State as AppState, Node } from '../../state';
|
||||
import { Row } from './';
|
||||
@@ -86,7 +86,7 @@ export class List extends React.Component<List.Props, {}> {
|
||||
<React.Fragment>
|
||||
<div className="List" style={{ height }}>
|
||||
<table>
|
||||
<Row.Header columns={selectedColumns} sortBy={sortBy} />
|
||||
<Row.HEADER columns={selectedColumns} sortBy={sortBy} />
|
||||
<tbody style={{ transform }}>
|
||||
{nodes.map((node) => (
|
||||
<Row
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../../common';
|
||||
import { Node } from '../../state';
|
||||
import { Persistent, PersistentSet } from '../../persist';
|
||||
import { HeaderCell, Column } from './';
|
||||
@@ -51,7 +51,7 @@ export class Row extends React.Component<Row.Props, Row.State> {
|
||||
Column.NETWORK_STATE,
|
||||
];
|
||||
|
||||
public static Header = (props: HeaderProps) => {
|
||||
public static HEADER = (props: HeaderProps) => {
|
||||
const { columns, sortBy } = props;
|
||||
const last = columns.length - 1;
|
||||
|
||||
@@ -91,7 +91,7 @@ export class Location extends React.Component<Location.Props, Location.State> {
|
||||
city,
|
||||
} = this.props.node;
|
||||
|
||||
let validatorRow = null;
|
||||
let validatorRow = <div />;
|
||||
|
||||
if (validator) {
|
||||
validatorRow = (
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../../common';
|
||||
import { Filter } from '../';
|
||||
import { State as AppState, Node } from '../../state';
|
||||
import { Location } from './';
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Maybe } from '@dotstats/common';
|
||||
import { Maybe } from '../../common';
|
||||
import { State as AppState } from '../../state';
|
||||
import { Setting } from './';
|
||||
import { Row } from '../List';
|
||||
@@ -1,5 +1,5 @@
|
||||
import * as React from 'react';
|
||||
import { Types, Maybe } from '@dotstats/common';
|
||||
import { Types, Maybe } from '../common';
|
||||
import sparkline from '@fnando/sparkline';
|
||||
import { Tooltip } from './';
|
||||
|
||||
@@ -79,7 +79,7 @@ export class Sparkline extends React.Component<Sparkline.Props, {}> {
|
||||
};
|
||||
|
||||
private onMouseMove = (
|
||||
event: MouseEvent,
|
||||
_event: MouseEvent,
|
||||
data: { value: number; index: number }
|
||||
) => {
|
||||
const { format, stamps } = this.props;
|
||||
|
Before Width: | Height: | Size: 366 B After Width: | Height: | Size: 366 B |
|
Before Width: | Height: | Size: 265 B After Width: | Height: | Size: 265 B |
|
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 145 B After Width: | Height: | Size: 145 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 142 B After Width: | Height: | Size: 142 B |
|
Before Width: | Height: | Size: 144 B After Width: | Height: | Size: 144 B |
|
Before Width: | Height: | Size: 297 B After Width: | Height: | Size: 297 B |
|
Before Width: | Height: | Size: 395 B After Width: | Height: | Size: 395 B |
|
Before Width: | Height: | Size: 250 B After Width: | Height: | Size: 250 B |
|
Before Width: | Height: | Size: 397 B After Width: | Height: | Size: 397 B |
|
Before Width: | Height: | Size: 352 B After Width: | Height: | Size: 352 B |
|
Before Width: | Height: | Size: 366 B After Width: | Height: | Size: 366 B |
|
Before Width: | Height: | Size: 283 B After Width: | Height: | Size: 283 B |
|
Before Width: | Height: | Size: 686 B After Width: | Height: | Size: 686 B |
|
Before Width: | Height: | Size: 268 B After Width: | Height: | Size: 268 B |
|
Before Width: | Height: | Size: 438 B After Width: | Height: | Size: 438 B |
|
Before Width: | Height: | Size: 588 B After Width: | Height: | Size: 588 B |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 646 B After Width: | Height: | Size: 646 B |