mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-17 13:07:32 +02:00
Add new squeaks available button to timeline (#1137)
* Add rpc method to subscribe to new squeaks * Got floating action button showing for refresh * Change spacing of refresh button * Load new squeaks in timeline from rpc subscription * Got refresh button correctly showing new squeaks from peer * Got refresh button action working correctly * Update frontend build
This commit is contained in:
parent
3cd21391ae
commit
ae65ff9320
19 changed files with 147 additions and 29 deletions
|
|
@ -8,11 +8,13 @@ import {
|
|||
Backdrop,
|
||||
CardHeader,
|
||||
Card,
|
||||
Box,
|
||||
} from '@material-ui/core';
|
||||
import { useTheme } from '@material-ui/styles';
|
||||
|
||||
import EditIcon from '@material-ui/icons/Edit';
|
||||
import ReplayIcon from '@material-ui/icons/Replay';
|
||||
import RefreshIcon from '@material-ui/icons/Refresh';
|
||||
|
||||
import Paper from '@material-ui/core/Paper';
|
||||
|
||||
|
|
@ -26,6 +28,7 @@ import SqueakList from '../../components/SqueakList';
|
|||
import {
|
||||
getTimelineSqueakDisplaysRequest,
|
||||
getNetworkRequest,
|
||||
subscribeSqueakDisplaysRequest,
|
||||
} from '../../squeakclient/requests';
|
||||
|
||||
const SQUEAKS_PER_PAGE = 10;
|
||||
|
|
@ -34,6 +37,7 @@ export default function TimelinePage() {
|
|||
const classes = useStyles();
|
||||
const theme = useTheme();
|
||||
const [squeaks, setSqueaks] = useState(null);
|
||||
const [newSqueaks, setNewSqueaks] = useState(null);
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [network, setNetwork] = useState('');
|
||||
const [waitingForTimeline, setWaitingForTimeline] = React.useState(false);
|
||||
|
|
@ -44,6 +48,9 @@ export default function TimelinePage() {
|
|||
setWaitingForTimeline(true);
|
||||
getTimelineSqueakDisplaysRequest(limit, blockHeight, squeakTime, squeakHash, handleLoadedTimeline, alertFailedRequest);
|
||||
};
|
||||
const subscribeNewSqueaks = () => {
|
||||
return subscribeSqueakDisplaysRequest(handleLoadedNewSqueak);
|
||||
};
|
||||
const getNetwork = () => {
|
||||
getNetworkRequest(setNetwork);
|
||||
};
|
||||
|
|
@ -60,6 +67,12 @@ export default function TimelinePage() {
|
|||
alert('Failed to load timeline.');
|
||||
};
|
||||
|
||||
const handleClickRefresh = () => {
|
||||
setSqueaks(null);
|
||||
setNewSqueaks(null);
|
||||
getSqueaks(SQUEAKS_PER_PAGE, null, null, null);
|
||||
};
|
||||
|
||||
const handleLoadedTimeline = (loadedSqueaks) => {
|
||||
setWaitingForTimeline(false);
|
||||
setSqueaks((prevSqueaks) => {
|
||||
|
|
@ -71,9 +84,23 @@ export default function TimelinePage() {
|
|||
});
|
||||
};
|
||||
|
||||
const handleLoadedNewSqueak = (newSqueak) => {
|
||||
setNewSqueaks((prevNewSqueaks) => {
|
||||
if (!prevNewSqueaks) {
|
||||
return [newSqueak];
|
||||
} else {
|
||||
return prevNewSqueaks.concat(newSqueak);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getSqueaks(SQUEAKS_PER_PAGE, null, null, null);
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
const stream = subscribeNewSqueaks();
|
||||
return () => stream.cancel();
|
||||
}, []);
|
||||
useEffect(() => {
|
||||
getNetwork();
|
||||
}, []);
|
||||
|
|
@ -162,14 +189,41 @@ export default function TimelinePage() {
|
|||
);
|
||||
}
|
||||
|
||||
function MakeSqueakContent() {
|
||||
return (
|
||||
<>
|
||||
<Fab color="secondary" aria-label="edit" className={classes.fab} onClick={handleClickOpen}>
|
||||
<EditIcon />
|
||||
</Fab>
|
||||
{MakeSqueakDialogContent()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
function LoadNewSqueaksContent() {
|
||||
return (
|
||||
<>
|
||||
<Box
|
||||
display="flex"
|
||||
width={600} height={0}
|
||||
alignItems="center"
|
||||
justifyContent="center"
|
||||
>
|
||||
<Fab variant="extended" color="secondary" aria-label="edit" className={classes.refreshFab} onClick={handleClickRefresh}>
|
||||
<RefreshIcon />
|
||||
Refresh ({newSqueaks.length} new squeaks)
|
||||
</Fab>
|
||||
</Box>
|
||||
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
{GridContent()}
|
||||
<Fab color="secondary" aria-label="edit" className={classes.fab} onClick={handleClickOpen}>
|
||||
<EditIcon />
|
||||
</Fab>
|
||||
|
||||
{MakeSqueakDialogContent()}
|
||||
{MakeSqueakContent()}
|
||||
{(newSqueaks) && LoadNewSqueaksContent()}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,12 @@ export default makeStyles((theme) => ({
|
|||
bottom: theme.spacing(4),
|
||||
right: theme.spacing(4),
|
||||
},
|
||||
refreshFab: {
|
||||
position: 'fixed',
|
||||
top: theme.spacing(14),
|
||||
margin: 'auto',
|
||||
justifyContent: 'center',
|
||||
},
|
||||
root: {
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ import {
|
|||
SubscribeReplySqueakDisplaysRequest,
|
||||
SubscribeAddressSqueakDisplaysRequest,
|
||||
SubscribeAncestorSqueakDisplaysRequest,
|
||||
SubscribeSqueakDisplaysRequest,
|
||||
} from '../proto/squeak_admin_pb';
|
||||
|
||||
import { SqueakAdminClient } from '../proto/squeak_admin_grpc_web_pb';
|
||||
|
|
@ -714,3 +715,19 @@ export function subscribeAncestorSqueakDisplaysRequest(hash, handleResponse) {
|
|||
console.log(stream);
|
||||
return stream;
|
||||
}
|
||||
|
||||
export function subscribeSqueakDisplaysRequest(handleResponse) {
|
||||
const request = new SubscribeSqueakDisplaysRequest();
|
||||
const stream = client.subscribeSqueakDisplays(request);
|
||||
stream.on('data', (response) => {
|
||||
handleResponse(response.getSqueakDisplayEntry());
|
||||
});
|
||||
stream.on('end', (end) => {
|
||||
// stream end signal
|
||||
console.log(end);
|
||||
alert(`Stream ended: ${end}`);
|
||||
});
|
||||
console.log('Stream object:');
|
||||
console.log(stream);
|
||||
return stream;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -300,6 +300,10 @@ service SqueakAdmin {
|
|||
*/
|
||||
rpc SubscribeAncestorSqueakDisplays (SubscribeAncestorSqueakDisplaysRequest) returns (stream GetAncestorSqueakDisplaysReply) {}
|
||||
|
||||
/** sqkadmin: `subscribesqueakdisplays`
|
||||
*/
|
||||
rpc SubscribeSqueakDisplays (SubscribeSqueakDisplaysRequest) returns (stream GetSqueakDisplayReply) {}
|
||||
|
||||
}
|
||||
|
||||
message CreateSigningProfileRequest {
|
||||
|
|
@ -1050,3 +1054,6 @@ message SubscribeAncestorSqueakDisplaysRequest {
|
|||
/// Hash of the squeak.
|
||||
string squeak_hash = 1;
|
||||
}
|
||||
|
||||
message SubscribeSqueakDisplaysRequest {
|
||||
}
|
||||
|
|
|
|||
|
|
@ -888,3 +888,20 @@ class SqueakAdminServerHandler(object):
|
|||
yield squeak_admin_pb2.GetAncestorSqueakDisplaysReply(
|
||||
squeak_display_entries=squeak_display_msgs
|
||||
)
|
||||
|
||||
def handle_subscribe_squeak_displays(self, request, stopped):
|
||||
logger.info("Handle subscribe squeak displays")
|
||||
squeak_display_stream = self.squeak_controller.subscribe_squeak_entries(
|
||||
stopped,
|
||||
)
|
||||
for squeak_display in squeak_display_stream:
|
||||
if squeak_display is None:
|
||||
yield squeak_admin_pb2.GetSqueakDisplayReply(
|
||||
squeak_display_entry=None
|
||||
)
|
||||
else:
|
||||
display_message = squeak_entry_to_message(
|
||||
squeak_display)
|
||||
yield squeak_admin_pb2.GetSqueakDisplayReply(
|
||||
squeak_display_entry=display_message
|
||||
)
|
||||
|
|
|
|||
|
|
@ -351,3 +351,15 @@ class SqueakAdminServerServicer(squeak_admin_pb2_grpc.SqueakAdminServicer):
|
|||
request,
|
||||
stopped,
|
||||
)
|
||||
|
||||
def SubscribeSqueakDisplays(self, request, context):
|
||||
stopped = threading.Event()
|
||||
|
||||
def on_rpc_done():
|
||||
logger.info("Stopping SubscribeSqueakDisplays.")
|
||||
stopped.set()
|
||||
context.add_callback(on_rpc_done)
|
||||
return self.handler.handle_subscribe_squeak_displays(
|
||||
request,
|
||||
stopped,
|
||||
)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.f8a2a2e3.chunk.js",
|
||||
"main.js.map": "/static/js/main.f8a2a2e3.chunk.js.map",
|
||||
"main.js": "/static/js/main.2197c77e.chunk.js",
|
||||
"main.js.map": "/static/js/main.2197c77e.chunk.js.map",
|
||||
"runtime-main.js": "/static/js/runtime-main.9f0ba400.js",
|
||||
"runtime-main.js.map": "/static/js/runtime-main.9f0ba400.js.map",
|
||||
"static/css/2.ea4ba2f0.chunk.css": "/static/css/2.ea4ba2f0.chunk.css",
|
||||
"static/js/2.11d0c00a.chunk.js": "/static/js/2.11d0c00a.chunk.js",
|
||||
"static/js/2.11d0c00a.chunk.js.map": "/static/js/2.11d0c00a.chunk.js.map",
|
||||
"static/js/2.d9a0f1f7.chunk.js": "/static/js/2.d9a0f1f7.chunk.js",
|
||||
"static/js/2.d9a0f1f7.chunk.js.map": "/static/js/2.d9a0f1f7.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"precache-manifest.8682697334869e1fa167e01e9b1fc118.js": "/precache-manifest.8682697334869e1fa167e01e9b1fc118.js",
|
||||
"precache-manifest.c43a430df16f036e3ff21e5318a5da98.js": "/precache-manifest.c43a430df16f036e3ff21e5318a5da98.js",
|
||||
"service-worker.js": "/service-worker.js",
|
||||
"static/css/2.ea4ba2f0.chunk.css.map": "/static/css/2.ea4ba2f0.chunk.css.map",
|
||||
"static/js/2.11d0c00a.chunk.js.LICENSE.txt": "/static/js/2.11d0c00a.chunk.js.LICENSE.txt",
|
||||
"static/js/2.d9a0f1f7.chunk.js.LICENSE.txt": "/static/js/2.d9a0f1f7.chunk.js.LICENSE.txt",
|
||||
"static/media/font-awesome.min.css": "/static/media/fontawesome-webfont.fee66e71.woff",
|
||||
"static/media/google.svg": "/static/media/google.695a3160.svg",
|
||||
"static/media/logo.svg": "/static/media/logo.a0185b04.svg"
|
||||
|
|
@ -19,7 +19,7 @@
|
|||
"entrypoints": [
|
||||
"static/js/runtime-main.9f0ba400.js",
|
||||
"static/css/2.ea4ba2f0.chunk.css",
|
||||
"static/js/2.11d0c00a.chunk.js",
|
||||
"static/js/main.f8a2a2e3.chunk.js"
|
||||
"static/js/2.d9a0f1f7.chunk.js",
|
||||
"static/js/main.2197c77e.chunk.js"
|
||||
]
|
||||
}
|
||||
|
|
@ -1 +1 @@
|
|||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeak Node</title><meta name="description" content="Squeak Node is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.ea4ba2f0.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.11d0c00a.chunk.js"></script><script src="/static/js/main.f8a2a2e3.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="shortcut icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no"/><meta name="theme-color" content="#000000"/><link rel="manifest" href="/manifest.json"/><title>Squeak Node</title><meta name="description" content="Squeak Node is a frontend for accessing a squeak node"><meta name="keywords" content="squeak, bitcoin, lightning"><meta name="author" content="Flatlogic LLC."><link href="/static/css/2.ea4ba2f0.chunk.css" rel="stylesheet"></head><body style="font-family:Roboto,sans-serif"><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,f,l=r[0],a=r[1],i=r[2],c=0,s=[];c<l.length;c++)f=l[c],Object.prototype.hasOwnProperty.call(o,f)&&o[f]&&s.push(o[f][0]),o[f]=0;for(n in a)Object.prototype.hasOwnProperty.call(a,n)&&(e[n]=a[n]);for(p&&p(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,l=1;l<t.length;l++){var a=t[l];0!==o[a]&&(n=!1)}n&&(u.splice(r--,1),e=f(f.s=t[0]))}return e}var n={},o={1:0},u=[];function f(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,f),t.l=!0,t.exports}f.m=e,f.c=n,f.d=function(e,r,t){f.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},f.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},f.t=function(e,r){if(1&r&&(e=f(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(f.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)f.d(t,n,function(r){return e[r]}.bind(null,n));return t},f.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return f.d(r,"a",r),r},f.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},f.p="/";var l=this["webpackJsonpsqueak-node-frontend"]=this["webpackJsonpsqueak-node-frontend"]||[],a=l.push.bind(l);l.push=r,l=l.slice();for(var i=0;i<l.length;i++)r(l[i]);var p=a;t()}([])</script><script src="/static/js/2.d9a0f1f7.chunk.js"></script><script src="/static/js/main.2197c77e.chunk.js"></script></body></html>
|
||||
|
|
@ -1,23 +1,23 @@
|
|||
self.__precacheManifest = (self.__precacheManifest || []).concat([
|
||||
{
|
||||
"revision": "add713cb0afc5f78101492d472d20086",
|
||||
"revision": "403fccc2dcba0974fde6cdb6524f4796",
|
||||
"url": "/index.html"
|
||||
},
|
||||
{
|
||||
"revision": "22e7334fbd3ece09f682",
|
||||
"revision": "f028a9224a31ac39b2f1",
|
||||
"url": "/static/css/2.ea4ba2f0.chunk.css"
|
||||
},
|
||||
{
|
||||
"revision": "22e7334fbd3ece09f682",
|
||||
"url": "/static/js/2.11d0c00a.chunk.js"
|
||||
"revision": "f028a9224a31ac39b2f1",
|
||||
"url": "/static/js/2.d9a0f1f7.chunk.js"
|
||||
},
|
||||
{
|
||||
"revision": "279b8724b89bf7d504758b3fa917239f",
|
||||
"url": "/static/js/2.11d0c00a.chunk.js.LICENSE.txt"
|
||||
"url": "/static/js/2.d9a0f1f7.chunk.js.LICENSE.txt"
|
||||
},
|
||||
{
|
||||
"revision": "de384a837e5e60ad80c4",
|
||||
"url": "/static/js/main.f8a2a2e3.chunk.js"
|
||||
"revision": "9509d08118323eb5ad7a",
|
||||
"url": "/static/js/main.2197c77e.chunk.js"
|
||||
},
|
||||
{
|
||||
"revision": "cc9816de5a8639d377ea",
|
||||
|
|
@ -14,7 +14,7 @@
|
|||
importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js");
|
||||
|
||||
importScripts(
|
||||
"/precache-manifest.8682697334869e1fa167e01e9b1fc118.js"
|
||||
"/precache-manifest.c43a430df16f036e3ff21e5318a5da98.js"
|
||||
);
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
|
|
|
|||
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
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
|
|
@ -709,3 +709,8 @@ class SqueakController:
|
|||
for item in self.new_squeak_listener.yield_items(stopped):
|
||||
if squeak_hash == get_hash(item):
|
||||
yield self.get_ancestor_squeak_entries(squeak_hash)
|
||||
|
||||
def subscribe_squeak_entries(self, stopped: threading.Event):
|
||||
for item in self.new_squeak_listener.yield_items(stopped):
|
||||
squeak_hash = get_hash(item)
|
||||
yield self.get_squeak_entry(squeak_hash)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue