mirror of
https://github.com/hoytech/strfry.git
synced 2025-06-18 17:27:11 +00:00
paginated user comment screens
This commit is contained in:
@ -595,11 +595,14 @@ struct UserEvents {
|
|||||||
};
|
};
|
||||||
|
|
||||||
std::vector<EventCluster> eventClusterArr;
|
std::vector<EventCluster> eventClusterArr;
|
||||||
|
uint64_t totalEvents = 0;
|
||||||
|
std::optional<uint64_t> timestampCutoff;
|
||||||
|
std::optional<uint64_t> nextResumeTime;
|
||||||
|
|
||||||
UserEvents(lmdb::txn &txn, Decompressor &decomp, const std::string &pubkey) : u(txn, decomp, pubkey) {
|
UserEvents(lmdb::txn &txn, Decompressor &decomp, const std::string &pubkey, uint64_t resumeTime) : u(txn, decomp, pubkey) {
|
||||||
flat_hash_map<std::string, EventCluster> eventClusters; // eventId (root) -> EventCluster
|
flat_hash_map<std::string, EventCluster> eventClusters; // eventId (root) -> EventCluster
|
||||||
|
|
||||||
env.generic_foreachFull(txn, env.dbi_Event__pubkeyKind, makeKey_StringUint64Uint64(pubkey, 1, MAX_U64), "", [&](std::string_view k, std::string_view v){
|
env.generic_foreachFull(txn, env.dbi_Event__pubkeyKind, makeKey_StringUint64Uint64(pubkey, 1, resumeTime), "", [&](std::string_view k, std::string_view v){
|
||||||
ParsedKey_StringUint64Uint64 parsedKey(k);
|
ParsedKey_StringUint64Uint64 parsedKey(k);
|
||||||
if (parsedKey.s != pubkey || parsedKey.n1 != 1) return false;
|
if (parsedKey.s != pubkey || parsedKey.n1 != 1) return false;
|
||||||
|
|
||||||
@ -617,6 +620,7 @@ struct UserEvents {
|
|||||||
cluster.isRootEventFromUser = rootEvent.getPubkey() == u.pubkey;
|
cluster.isRootEventFromUser = rootEvent.getPubkey() == u.pubkey;
|
||||||
cluster.rootEventTimestamp = rootEvent.getCreatedAt();
|
cluster.rootEventTimestamp = rootEvent.getCreatedAt();
|
||||||
cluster.eventCache.emplace(rootId, std::move(rootEvent));
|
cluster.eventCache.emplace(rootId, std::move(rootEvent));
|
||||||
|
totalEvents++;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (ev.root.size()) {
|
if (ev.root.size()) {
|
||||||
@ -635,6 +639,7 @@ struct UserEvents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
eventClusters.at(ev.root).eventCache.emplace(id, std::move(ev));
|
eventClusters.at(ev.root).eventCache.emplace(id, std::move(ev));
|
||||||
|
totalEvents++;
|
||||||
} else {
|
} else {
|
||||||
// Event is root
|
// Event is root
|
||||||
|
|
||||||
@ -643,6 +648,15 @@ struct UserEvents {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (timestampCutoff) {
|
||||||
|
if (*timestampCutoff != parsedKey.n2) {
|
||||||
|
nextResumeTime = *timestampCutoff - 1;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else if (totalEvents > 100) {
|
||||||
|
timestampCutoff = parsedKey.n2;
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}, true);
|
}, true);
|
||||||
|
|
||||||
@ -666,9 +680,11 @@ struct UserEvents {
|
|||||||
struct {
|
struct {
|
||||||
std::vector<TemplarResult> &renderedThreads;
|
std::vector<TemplarResult> &renderedThreads;
|
||||||
User &u;
|
User &u;
|
||||||
|
std::optional<uint64_t> nextResumeTime;
|
||||||
} ctx = {
|
} ctx = {
|
||||||
renderedThreads,
|
renderedThreads,
|
||||||
u,
|
u,
|
||||||
|
nextResumeTime,
|
||||||
};
|
};
|
||||||
|
|
||||||
return tmpl::user::comments(ctx);
|
return tmpl::user::comments(ctx);
|
||||||
|
@ -217,7 +217,14 @@ HTTPResponse WebServer::generateReadResponse(lmdb::txn &txn, Decompressor &decom
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (u.path[2] == "notes") {
|
if (u.path[2] == "notes") {
|
||||||
UserEvents uc(txn, decomp, userPubkey);
|
uint64_t resumeTime = MAX_U64;
|
||||||
|
|
||||||
|
try {
|
||||||
|
auto resumeTimeStr = u.lookupQuery("next");
|
||||||
|
if (resumeTimeStr) resumeTime = std::stoull(std::string(*resumeTimeStr));
|
||||||
|
} catch(...) {}
|
||||||
|
|
||||||
|
UserEvents uc(txn, decomp, userPubkey, resumeTime);
|
||||||
title = std::string("notes: ") + uc.u.username;
|
title = std::string("notes: ") + uc.u.username;
|
||||||
body = uc.render(txn, decomp);
|
body = uc.render(txn, decomp);
|
||||||
} else if (u.path[2] == "export.jsonl") {
|
} else if (u.path[2] == "export.jsonl") {
|
||||||
|
@ -22,6 +22,34 @@ struct Url {
|
|||||||
|
|
||||||
if (u.size()) path.emplace_back(u);
|
if (u.size()) path.emplace_back(u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<std::string_view> lookupQuery(std::string_view key) {
|
||||||
|
std::string_view curr = query;
|
||||||
|
|
||||||
|
while (curr.size()) {
|
||||||
|
auto nextPos = curr.find("&");
|
||||||
|
|
||||||
|
{
|
||||||
|
std::string_view currKV = nextPos == std::string::npos ? curr : curr.substr(0, nextPos);
|
||||||
|
std::string_view k, v;
|
||||||
|
|
||||||
|
auto equalsPos = currKV.find("=");
|
||||||
|
if (equalsPos == std::string::npos) {
|
||||||
|
k = currKV;
|
||||||
|
} else {
|
||||||
|
k = currKV.substr(0, equalsPos);
|
||||||
|
v = currKV.substr(equalsPos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (k == key) return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextPos == std::string::npos) break;
|
||||||
|
curr = curr.substr(nextPos + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
inline std::string renderTimestamp(uint64_t now, uint64_t ts) {
|
inline std::string renderTimestamp(uint64_t now, uint64_t ts) {
|
||||||
|
@ -180,11 +180,18 @@ table.vert {
|
|||||||
|
|
||||||
/* user comments */
|
/* user comments */
|
||||||
|
|
||||||
.user-comments > div {
|
.user-comments {
|
||||||
|
.note-thread {
|
||||||
margin-bottom: 30px;
|
margin-bottom: 30px;
|
||||||
border-bottom: 1px solid black;
|
border-bottom: 1px solid black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.more-notes {
|
||||||
|
margin-left: 20px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* event */
|
/* event */
|
||||||
|
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
<div class="user-comments">
|
<div class="user-comments">
|
||||||
<h2>
|
<h2 class="notes-header">
|
||||||
Notes by <a href="/u/$(ctx.u.npubId)">$(ctx.u.username)</a>
|
Notes by <a href="/u/$(ctx.u.npubId)">$(ctx.u.username)</a>
|
||||||
| <a href="/u/$(ctx.u.npubId)/export.jsonl">export</a>
|
| <a href="/u/$(ctx.u.npubId)/export.jsonl">export</a>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div> @(auto &r : ctx.renderedThreads)
|
<div class="note-thread"> @(auto &r : ctx.renderedThreads)
|
||||||
$(r)
|
$(r)
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="more-notes"> ?(ctx.nextResumeTime)
|
||||||
|
<a href="/u/$(ctx.u.npubId)/notes?next=$(*ctx.nextResumeTime)">More notes by $(ctx.u.username)</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
Reference in New Issue
Block a user