Add pagination to get address squeaks rpc (#1173)

* Add pagination to get address squeaks rpc

* Implement frontend pagination for address squeaks page

* Got pagination working on address squeaks page

* Update frontend build

* Run frontend lint

* Update frontend build
This commit is contained in:
Jonathan Zernik 2021-09-03 17:00:38 -07:00 committed by GitHub
parent 8f55a3729f
commit fd9a75b417
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
22 changed files with 188 additions and 53 deletions

View file

@ -16,6 +16,7 @@ import Paper from '@material-ui/core/Paper';
import FaceIcon from '@material-ui/icons/Face';
import GetAppIcon from '@material-ui/icons/GetApp';
import ReplayIcon from '@material-ui/icons/Replay';
import CreateContactProfileDialog from '../../components/CreateContactProfileDialog';
import SqueakList from '../../components/SqueakList';
@ -33,6 +34,8 @@ import {
goToProfilePage,
} from '../../navigation/navigation';
const SQUEAKS_PER_PAGE = 10;
export default function SqueakAddressPage() {
const classes = useStyles();
const history = useHistory();
@ -46,9 +49,9 @@ export default function SqueakAddressPage() {
const getSqueakProfile = (address) => {
getSqueakProfileByAddressRequest(address, setSqueakProfile);
};
const getSqueaks = (address) => {
const getSqueaks = (address, limit, blockHeight, squeakTime, squeakHash) => {
setWaitingForSqueaks(true);
getAddressSqueakDisplaysRequest(address, handleLoadedAddressSqueaks);
getAddressSqueakDisplaysRequest(address, limit, blockHeight, squeakTime, squeakHash, handleLoadedAddressSqueaks);
};
const subscribeSqueaks = (address) => subscribeAddressSqueakDisplaysRequest(address, (resp) => {
setSqueaks((prevSqueaks) => [resp].concat(prevSqueaks));
@ -59,7 +62,12 @@ export default function SqueakAddressPage() {
const handleLoadedAddressSqueaks = (loadedAddressSqueaks) => {
setWaitingForSqueaks(false);
setSqueaks(loadedAddressSqueaks);
setSqueaks((prevSqueaks) => {
if (!prevSqueaks) {
return loadedAddressSqueaks;
}
return prevSqueaks.concat(loadedAddressSqueaks);
});
};
const handleClickOpenCreateContactProfileDialog = () => {
@ -82,7 +90,7 @@ export default function SqueakAddressPage() {
getSqueakProfile(address);
}, [address]);
useEffect(() => {
getSqueaks(address);
getSqueaks(address, SQUEAKS_PER_PAGE, null, null, null);
}, [address]);
useEffect(() => {
const stream = subscribeSqueaks(address);
@ -178,6 +186,7 @@ export default function SqueakAddressPage() {
? SqueaksContent()
: NoSqueaksContent()}
</Paper>
{ViewMoreSqueaksButton()}
</Grid>
<Grid item xs={12} sm={3}>
<Paper className={classes.paper} />
@ -225,6 +234,36 @@ export default function SqueakAddressPage() {
);
}
function ViewMoreSqueaksButton() {
return (
<>
<Grid item xs={12}>
<div className={classes.wrapper}>
{!waitingForSqueaks
&& (
<Button
variant="contained"
color="primary"
disabled={waitingForSqueaks}
onClick={() => {
const latestSqueak = squeaks.slice(-1).pop();
const latestSqueakHeight = (latestSqueak ? latestSqueak.getBlockHeight() : null);
const latestSqueakTime = (latestSqueak ? latestSqueak.getSqueakTime() : null);
const latestSqueakHash = (latestSqueak ? latestSqueak.getSqueakHash() : null);
getSqueaks(address, SQUEAKS_PER_PAGE, latestSqueakHeight, latestSqueakTime, latestSqueakHash);
}}
>
<ReplayIcon />
View more squeaks
</Button>
)}
{waitingForSqueaks && <CircularProgress size={48} className={classes.buttonProgress} />}
</div>
</Grid>
</>
);
}
return (
<>
{SqueakProfileContent()}

View file

@ -1,4 +1,5 @@
import { makeStyles } from '@material-ui/styles';
import { green } from '@material-ui/core/colors';
export default makeStyles((theme) => ({
dashedBorder: {
@ -12,9 +13,44 @@ export default makeStyles((theme) => ({
text: {
marginBottom: theme.spacing(2),
},
oppositeContent: {
// TODO: adjust this value accordingly
flex: 0.0,
padding: 0,
fab: {
position: 'fixed',
bottom: theme.spacing(4),
right: theme.spacing(4),
},
refreshFab: {
position: 'fixed',
top: theme.spacing(14),
margin: 'auto',
justifyContent: 'center',
},
root: {
display: 'flex',
alignItems: 'center',
},
wrapper: {
margin: theme.spacing(1),
position: 'relative',
},
buttonSuccess: {
backgroundColor: green[500],
'&:hover': {
backgroundColor: green[700],
},
},
fabProgress: {
color: green[500],
position: 'absolute',
top: -6,
left: -6,
zIndex: 1,
},
buttonProgress: {
color: green[500],
position: 'absolute',
top: '50%',
left: '50%',
marginTop: -12,
marginLeft: -12,
},
}));

View file

@ -372,9 +372,13 @@ export function getSqueakProfileByAddressRequest(address, handleResponse) {
});
}
export function getAddressSqueakDisplaysRequest(address, handleResponse) {
export function getAddressSqueakDisplaysRequest(address, limit, blockHeight, squeakTime, squeakHash, handleResponse) {
const request = new GetAddressSqueakDisplaysRequest();
request.setAddress(address);
request.setLimit(limit);
request.setBlockHeight(blockHeight);
request.setSqueakTime(squeakTime);
request.setSqueakHash(squeakHash);
client.getAddressSqueakDisplays(request, {}, (err, response) => {
handleResponse(response.getSqueakDisplayEntriesList());
});

View file

@ -11,3 +11,4 @@ pytest -s tests
#pytest -s tests -k "test_delete_squeak"
#pytest -s tests -k "test_subscribe_squeaks"
#pytest -s tests -k "test_download_squeaks_for_address"
#pytest -s tests -k "test_make_squeak"

View file

@ -135,7 +135,9 @@ def test_make_squeak(admin_stub, signing_profile_id):
# Get all squeak displays for the known address
get_address_squeak_display_response = admin_stub.GetAddressSqueakDisplays(
squeak_admin_pb2.GetAddressSqueakDisplaysRequest(
address=squeak_profile_address)
address=squeak_profile_address,
limit=100,
),
)
assert len(get_address_squeak_display_response.squeak_display_entries) == 1
for (

View file

@ -571,6 +571,18 @@ message GetTimelineSqueakDisplaysReply {
message GetAddressSqueakDisplaysRequest {
/// The address
string address = 1;
/// Limit number of results
int32 limit = 2;
/// Block height
int32 block_height = 3;
/// Squeak time
int64 squeak_time = 4;
/// Hash of the squeak.
string squeak_hash = 5;
}
message GetAddressSqueakDisplaysReply {

View file

@ -20,7 +20,6 @@
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import logging
import sys
from proto import squeak_admin_pb2
from squeaknode.admin.messages import connected_peer_to_message
@ -351,15 +350,31 @@ class SqueakAdminServerHandler(object):
def handle_get_squeak_display_entries_for_address(self, request):
address = request.address
min_block = 0
max_block = sys.maxsize
logger.info(
"Handle get squeak display entries for address: {}".format(address))
limit = request.limit
block_height = request.block_height
squeak_time = request.squeak_time
squeak_hash_str = request.squeak_hash
squeak_hash = bytes.fromhex(
squeak_hash_str) if squeak_hash_str else None
logger.info("""Handle get squeak display entries for address: {} with
limit: {}
block_height: {}
squeak_time: {}
squeak_hash: {}
""".format(
address,
limit,
block_height,
squeak_time,
squeak_hash,
))
squeak_entries = (
self.squeak_controller.get_squeak_entries_for_address(
address,
min_block,
max_block,
limit,
block_height,
squeak_time,
squeak_hash,
)
)
logger.info(

View file

@ -1,25 +1,25 @@
{
"files": {
"main.js": "/static/js/main.d102ea6f.chunk.js",
"main.js.map": "/static/js/main.d102ea6f.chunk.js.map",
"main.js": "/static/js/main.00daa4a7.chunk.js",
"main.js.map": "/static/js/main.00daa4a7.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.27af5173.chunk.js": "/static/js/2.27af5173.chunk.js",
"static/js/2.27af5173.chunk.js.map": "/static/js/2.27af5173.chunk.js.map",
"static/css/2.15110fae.chunk.css": "/static/css/2.15110fae.chunk.css",
"static/js/2.cc10b99b.chunk.js": "/static/js/2.cc10b99b.chunk.js",
"static/js/2.cc10b99b.chunk.js.map": "/static/js/2.cc10b99b.chunk.js.map",
"index.html": "/index.html",
"precache-manifest.0f8a4cb088b97557f0dbc665563e44e3.js": "/precache-manifest.0f8a4cb088b97557f0dbc665563e44e3.js",
"precache-manifest.fede21470d7df7e28ff05544ed997393.js": "/precache-manifest.fede21470d7df7e28ff05544ed997393.js",
"service-worker.js": "/service-worker.js",
"static/css/2.ea4ba2f0.chunk.css.map": "/static/css/2.ea4ba2f0.chunk.css.map",
"static/js/2.27af5173.chunk.js.LICENSE.txt": "/static/js/2.27af5173.chunk.js.LICENSE.txt",
"static/css/2.15110fae.chunk.css.map": "/static/css/2.15110fae.chunk.css.map",
"static/js/2.cc10b99b.chunk.js.LICENSE.txt": "/static/js/2.cc10b99b.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"
},
"entrypoints": [
"static/js/runtime-main.9f0ba400.js",
"static/css/2.ea4ba2f0.chunk.css",
"static/js/2.27af5173.chunk.js",
"static/js/main.d102ea6f.chunk.js"
"static/css/2.15110fae.chunk.css",
"static/js/2.cc10b99b.chunk.js",
"static/js/main.00daa4a7.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.27af5173.chunk.js"></script><script src="/static/js/main.d102ea6f.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.15110fae.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.cc10b99b.chunk.js"></script><script src="/static/js/main.00daa4a7.chunk.js"></script></body></html>

View file

@ -1,23 +1,23 @@
self.__precacheManifest = (self.__precacheManifest || []).concat([
{
"revision": "2abb3e1841e2714a857fc1b9ad78b218",
"revision": "19471425b52a7faf7f559cb8bfb18cf1",
"url": "/index.html"
},
{
"revision": "872f0bd685e845499d74",
"url": "/static/css/2.ea4ba2f0.chunk.css"
"revision": "3bd873c4f94a371ab8b4",
"url": "/static/css/2.15110fae.chunk.css"
},
{
"revision": "872f0bd685e845499d74",
"url": "/static/js/2.27af5173.chunk.js"
"revision": "3bd873c4f94a371ab8b4",
"url": "/static/js/2.cc10b99b.chunk.js"
},
{
"revision": "279b8724b89bf7d504758b3fa917239f",
"url": "/static/js/2.27af5173.chunk.js.LICENSE.txt"
"url": "/static/js/2.cc10b99b.chunk.js.LICENSE.txt"
},
{
"revision": "9cf94de8dd0fbeca0178",
"url": "/static/js/main.d102ea6f.chunk.js"
"revision": "cf885cfecdc4665bc56b",
"url": "/static/js/main.00daa4a7.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.0f8a4cb088b97557f0dbc665563e44e3.js"
"/precache-manifest.fede21470d7df7e28ff05544ed997393.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

View file

@ -315,9 +315,17 @@ class SqueakDb:
return [self._parse_squeak_entry(row) for row in rows]
def get_squeak_entries_for_address(
self, address: str, min_block: int, max_block: int
self,
address: str,
limit: int,
block_height: int,
squeak_time: int,
squeak_hash: bytes,
) -> List[SqueakEntry]:
""" Get a squeak. """
block_height = block_height or MAX_INT
squeak_time = squeak_time or MAX_INT
squeak_hash = squeak_hash or MAX_HASH
s = (
select([self.squeaks, self.profiles])
.select_from(
@ -327,12 +335,23 @@ class SqueakDb:
)
)
.where(self.squeaks.c.author_address == address)
.where(self.squeaks.c.n_block_height >= min_block)
.where(self.squeaks.c.n_block_height <= max_block)
.where(
tuple_(
self.squeaks.c.n_block_height,
self.squeaks.c.n_time,
self.squeaks.c.hash,
) < tuple_(
block_height,
squeak_time,
squeak_hash,
)
)
.order_by(
self.squeaks.c.n_block_height.desc(),
self.squeaks.c.n_time.desc(),
self.squeaks.c.hash.desc(),
)
.limit(limit)
)
with self.get_connection() as connection:
result = connection.execute(s)

View file

@ -440,12 +440,19 @@ class SqueakController:
return self.squeak_db.get_liked_squeak_entries()
def get_squeak_entries_for_address(
self, address: str, min_block: int, max_block: int
self,
address: str,
limit: int,
block_height: int,
squeak_time: int,
squeak_hash: bytes,
) -> List[SqueakEntry]:
return self.squeak_db.get_squeak_entries_for_address(
address,
min_block,
max_block,
limit,
block_height,
squeak_time,
squeak_hash,
)
def get_ancestor_squeak_entries(self, squeak_hash: bytes) -> List[SqueakEntry]: