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:
Jonathan Zernik 2021-08-31 23:40:26 -07:00 committed by GitHub
parent 3cd21391ae
commit ae65ff9320
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 147 additions and 29 deletions

View file

@ -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()}
</>
);
}

View file

@ -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',

View file

@ -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;
}

View file

@ -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 {
}

View file

@ -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
)

View file

@ -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,
)

View file

@ -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"
]
}

View file

@ -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>

View file

@ -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",

View file

@ -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

View file

@ -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)