mirror of
https://github.com/yzernik/squeaknode.git
synced 2026-08-16 13:01:04 +02:00
Add pagination (#1073)
* Got tuple comparison for timeline pagination query working * Include limit parameter in get timeline rpc * Got view more squeaks frontend button working * Got basic pagination working * Include squeak time in display rpc struct * Got pagination working * Fix sql query to break ties manually in comparison * Update frontend build
This commit is contained in:
parent
623aada9a0
commit
0a8d30d5fc
17 changed files with 150 additions and 25 deletions
|
|
@ -55,6 +55,7 @@ import {
|
|||
goToSqueakAddressPage,
|
||||
} from "../../navigation/navigation"
|
||||
|
||||
const SQUEAKS_PER_PAGE = 10;
|
||||
|
||||
export default function TimelinePage() {
|
||||
var classes = useStyles();
|
||||
|
|
@ -66,7 +67,7 @@ export default function TimelinePage() {
|
|||
const history = useHistory();
|
||||
|
||||
const getSqueaks = () => {
|
||||
getTimelineSqueakDisplaysRequest(setSqueaks);
|
||||
getTimelineSqueakDisplaysRequest(SQUEAKS_PER_PAGE, null, null, null, setSqueaks);
|
||||
};
|
||||
const getNetwork = () => {
|
||||
getNetworkRequest(setNetwork);
|
||||
|
|
@ -114,6 +115,35 @@ export default function TimelinePage() {
|
|||
network={network}
|
||||
setSqueaksFn={setSqueaks}
|
||||
></SqueakList>
|
||||
{(squeaks.length > 0) && ViewMoreSqueaksButton()}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
||||
function ViewMoreSqueaksButton() {
|
||||
return (
|
||||
<>
|
||||
<Grid item xs={12}>
|
||||
<div className={classes.root}>
|
||||
<Button
|
||||
variant="contained"
|
||||
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);
|
||||
console.log(latestSqueakHeight);
|
||||
console.log(latestSqueakTime);
|
||||
console.log(latestSqueakHash);
|
||||
getTimelineSqueakDisplaysRequest(SQUEAKS_PER_PAGE, latestSqueakHeight, latestSqueakTime, latestSqueakHash, (resp) => {
|
||||
// TODO: nothing maybe
|
||||
console.log(resp);
|
||||
setSqueaks(squeaks.concat(resp));
|
||||
});
|
||||
}}>View more squeaks
|
||||
</Button>
|
||||
</div>
|
||||
</Grid>
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -155,8 +155,12 @@ export function getUserRequest(handleResponse) {
|
|||
});
|
||||
}
|
||||
|
||||
export function getTimelineSqueakDisplaysRequest(handleResponse) {
|
||||
export function getTimelineSqueakDisplaysRequest(limit, blockHeight, squeakTime, squeakHash, handleResponse) {
|
||||
var request = new GetTimelineSqueakDisplaysRequest()
|
||||
request.setLimit(limit);
|
||||
request.setBlockHeight(blockHeight);
|
||||
request.setSqueakTime(squeakTime);
|
||||
request.setSqueakHash(squeakHash);
|
||||
client.getTimelineSqueakDisplays(request, {}, (err, response) => {
|
||||
handleResponse(response.getSqueakDisplayEntriesList());
|
||||
});
|
||||
|
|
|
|||
|
|
@ -372,7 +372,9 @@ def test_get_following_squeaks(
|
|||
|
||||
# Get all squeak displays for the known address
|
||||
get_timeline_squeak_display_response = admin_stub.GetTimelineSqueakDisplays(
|
||||
squeak_admin_pb2.GetTimelineSqueakDisplaysRequest()
|
||||
squeak_admin_pb2.GetTimelineSqueakDisplaysRequest(
|
||||
limit=100,
|
||||
)
|
||||
)
|
||||
assert len(get_timeline_squeak_display_response.squeak_display_entries) >= 1
|
||||
for (
|
||||
|
|
|
|||
|
|
@ -485,20 +485,34 @@ message SqueakDisplayEntry {
|
|||
/// Block time
|
||||
int64 block_time = 8;
|
||||
|
||||
/// Squeak time
|
||||
int64 squeak_time = 9;
|
||||
|
||||
/// The author name
|
||||
string author_address = 9;
|
||||
string author_address = 10;
|
||||
|
||||
/// Is author address known
|
||||
bool is_author_known = 10;
|
||||
bool is_author_known = 11;
|
||||
|
||||
/// The author name
|
||||
SqueakProfile author = 11;
|
||||
SqueakProfile author = 12;
|
||||
|
||||
/// Liked time
|
||||
int64 liked_time_s = 12;
|
||||
int64 liked_time_s = 13;
|
||||
}
|
||||
|
||||
message GetTimelineSqueakDisplaysRequest {
|
||||
/// Limit number of results
|
||||
int32 limit = 1;
|
||||
|
||||
/// Block height
|
||||
int32 block_height = 2;
|
||||
|
||||
/// Squeak time
|
||||
int64 squeak_time = 3;
|
||||
|
||||
/// Hash of the squeak.
|
||||
string squeak_hash = 4;
|
||||
}
|
||||
|
||||
message GetTimelineSqueakDisplaysReply {
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ def squeak_entry_to_message(squeak_entry: SqueakEntry) -> squeak_admin_pb2.Squea
|
|||
block_height=squeak_entry.block_height,
|
||||
block_hash=squeak_entry.block_hash.hex(),
|
||||
block_time=squeak_entry.block_time,
|
||||
squeak_time=squeak_entry.squeak_time,
|
||||
is_reply=is_reply,
|
||||
reply_to=reply_to, # type: ignore
|
||||
author_address=squeak_entry.address,
|
||||
|
|
|
|||
|
|
@ -283,9 +283,30 @@ class SqueakAdminServerHandler(object):
|
|||
)
|
||||
|
||||
def handle_get_timeline_squeak_display_entries(self, request):
|
||||
logger.info("Handle get timeline squeak display entries.")
|
||||
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 timeline squeak display entries with
|
||||
limit: {}
|
||||
block_height: {}
|
||||
squeak_time: {}
|
||||
squeak_hash: {}
|
||||
""".format(
|
||||
limit,
|
||||
block_height,
|
||||
squeak_time,
|
||||
squeak_hash,
|
||||
))
|
||||
squeak_entries = (
|
||||
self.squeak_controller.get_timeline_squeak_entries()
|
||||
self.squeak_controller.get_timeline_squeak_entries(
|
||||
limit,
|
||||
block_height,
|
||||
squeak_time,
|
||||
squeak_hash,
|
||||
)
|
||||
)
|
||||
logger.info(
|
||||
"Got number of timeline squeak entries: {}".format(
|
||||
|
|
@ -649,7 +670,7 @@ class SqueakAdminServerHandler(object):
|
|||
squeak_display_msgs = [
|
||||
squeak_entry_to_message(entry) for entry in squeak_entries
|
||||
]
|
||||
return squeak_admin_pb2.GetTimelineSqueakDisplaysReply(
|
||||
return squeak_admin_pb2.GetLikedSqueakDisplaysReply(
|
||||
squeak_display_entries=squeak_display_msgs
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"files": {
|
||||
"main.js": "/static/js/main.bfb223c5.chunk.js",
|
||||
"main.js.map": "/static/js/main.bfb223c5.chunk.js.map",
|
||||
"main.js": "/static/js/main.10fd6ba6.chunk.js",
|
||||
"main.js.map": "/static/js/main.10fd6ba6.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.ec475cb5.chunk.js": "/static/js/2.ec475cb5.chunk.js",
|
||||
"static/js/2.ec475cb5.chunk.js.map": "/static/js/2.ec475cb5.chunk.js.map",
|
||||
"index.html": "/index.html",
|
||||
"precache-manifest.d2a8205cf40a06153e5874961a1e8606.js": "/precache-manifest.d2a8205cf40a06153e5874961a1e8606.js",
|
||||
"precache-manifest.0f8fa25748364c540ce6365137ec0feb.js": "/precache-manifest.0f8fa25748364c540ce6365137ec0feb.js",
|
||||
"service-worker.js": "/service-worker.js",
|
||||
"static/css/2.ea4ba2f0.chunk.css.map": "/static/css/2.ea4ba2f0.chunk.css.map",
|
||||
"static/js/2.ec475cb5.chunk.js.LICENSE.txt": "/static/js/2.ec475cb5.chunk.js.LICENSE.txt",
|
||||
|
|
@ -20,6 +20,6 @@
|
|||
"static/js/runtime-main.9f0ba400.js",
|
||||
"static/css/2.ea4ba2f0.chunk.css",
|
||||
"static/js/2.ec475cb5.chunk.js",
|
||||
"static/js/main.bfb223c5.chunk.js"
|
||||
"static/js/main.10fd6ba6.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.ec475cb5.chunk.js"></script><script src="/static/js/main.bfb223c5.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.ec475cb5.chunk.js"></script><script src="/static/js/main.10fd6ba6.chunk.js"></script></body></html>
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
self.__precacheManifest = (self.__precacheManifest || []).concat([
|
||||
{
|
||||
"revision": "99ccc6cb2113f0a4951619caa302e43b",
|
||||
"revision": "b5011907348412eb78b65d9d21258ae6",
|
||||
"url": "/index.html"
|
||||
},
|
||||
{
|
||||
|
|
@ -16,8 +16,8 @@ self.__precacheManifest = (self.__precacheManifest || []).concat([
|
|||
"url": "/static/js/2.ec475cb5.chunk.js.LICENSE.txt"
|
||||
},
|
||||
{
|
||||
"revision": "d7ae9f2d5721cc3f45f3",
|
||||
"url": "/static/js/main.bfb223c5.chunk.js"
|
||||
"revision": "16b19bbda111a5670399",
|
||||
"url": "/static/js/main.10fd6ba6.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.d2a8205cf40a06153e5874961a1e8606.js"
|
||||
"/precache-manifest.0f8fa25748364c540ce6365137ec0feb.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
|
|
@ -10,6 +10,7 @@ class SqueakEntry(NamedTuple):
|
|||
block_height: int
|
||||
block_hash: bytes
|
||||
block_time: int
|
||||
squeak_time: int
|
||||
reply_to: Optional[bytes]
|
||||
is_unlocked: bool
|
||||
squeak_profile: Optional[SqueakProfile]
|
||||
|
|
|
|||
|
|
@ -11,6 +11,8 @@ import sqlalchemy
|
|||
from bitcoin.core import CBlockHeader
|
||||
from sqlalchemy import func
|
||||
from sqlalchemy import literal
|
||||
from sqlalchemy.sql import and_
|
||||
from sqlalchemy.sql import or_
|
||||
from sqlalchemy.sql import select
|
||||
from squeak.core import CSqueak
|
||||
|
||||
|
|
@ -31,6 +33,10 @@ from squeaknode.db.migrations import run_migrations
|
|||
from squeaknode.db.models import Models
|
||||
|
||||
|
||||
MAX_INT = 999999999
|
||||
MAX_HASH = b'\xff' * 32
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
@ -212,8 +218,28 @@ class SqueakDb:
|
|||
return None
|
||||
return self._parse_squeak_entry(row)
|
||||
|
||||
def get_timeline_squeak_entries(self) -> List[SqueakEntry]:
|
||||
def get_timeline_squeak_entries(
|
||||
self,
|
||||
limit: int,
|
||||
block_height: int = MAX_INT,
|
||||
squeak_time: int = MAX_INT,
|
||||
squeak_hash: bytes = MAX_HASH,
|
||||
) -> List[SqueakEntry]:
|
||||
""" Get all followed squeaks. """
|
||||
block_height = block_height or MAX_INT
|
||||
squeak_time = squeak_time or MAX_INT
|
||||
squeak_hash = squeak_hash or MAX_HASH
|
||||
logger.info("""Timeline db query with
|
||||
limit: {}
|
||||
block_height: {}
|
||||
squeak_time: {}
|
||||
squeak_hash: {}
|
||||
""".format(
|
||||
limit,
|
||||
block_height,
|
||||
squeak_time,
|
||||
squeak_hash.hex(),
|
||||
))
|
||||
s = (
|
||||
select([self.squeaks, self.profiles])
|
||||
.select_from(
|
||||
|
|
@ -222,10 +248,24 @@ class SqueakDb:
|
|||
self.profiles.c.address == self.squeaks.c.author_address,
|
||||
)
|
||||
)
|
||||
.where(or_(
|
||||
self.squeaks.c.n_block_height < block_height,
|
||||
and_(
|
||||
self.squeaks.c.n_block_height == block_height,
|
||||
self.squeaks.c.n_time < squeak_time,
|
||||
),
|
||||
and_(
|
||||
self.squeaks.c.n_block_height == block_height,
|
||||
self.squeaks.c.n_time == squeak_time,
|
||||
self.squeaks.c.hash < 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)
|
||||
|
|
@ -1103,6 +1143,7 @@ class SqueakDb:
|
|||
block_height=row["n_block_height"],
|
||||
block_hash=(row["hash_block"]),
|
||||
block_time=row["block_time"],
|
||||
squeak_time=row["n_time"],
|
||||
reply_to=reply_to,
|
||||
is_unlocked=is_locked,
|
||||
liked_time=liked_time_s,
|
||||
|
|
|
|||
|
|
@ -373,8 +373,19 @@ class SqueakController:
|
|||
def get_squeak_entry(self, squeak_hash: bytes) -> Optional[SqueakEntry]:
|
||||
return self.squeak_db.get_squeak_entry(squeak_hash)
|
||||
|
||||
def get_timeline_squeak_entries(self) -> List[SqueakEntry]:
|
||||
return self.squeak_db.get_timeline_squeak_entries()
|
||||
def get_timeline_squeak_entries(
|
||||
self,
|
||||
limit: int,
|
||||
block_height: int,
|
||||
squeak_time: int,
|
||||
squeak_hash: bytes,
|
||||
) -> List[SqueakEntry]:
|
||||
return self.squeak_db.get_timeline_squeak_entries(
|
||||
limit,
|
||||
block_height,
|
||||
squeak_time,
|
||||
squeak_hash,
|
||||
)
|
||||
|
||||
def get_liked_squeak_entries(self) -> List[SqueakEntry]:
|
||||
return self.squeak_db.get_liked_squeak_entries()
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue