Jev picks a Signal's icon, on the server's key, and each Signal counts its items (#263)
Jev chooses among options and cannot name one, so the page searches Font Awesome's index for each word of the Signal's name, words and sentence, the best six each, and offers the likeliest 40. POST /api/signals/icon asks a choice question on the server's TYPESAFE_KEY and answers with one of those offered, never another. "Let Jev pick" in the icon picker, and a Signal made without an icon gets one a moment after. Tried against TypeSafe: for AI Development, laptop-code 0.45 just ahead of robot 0.40. Each Signal's row says "12 items · 3 unread", as a feed's row counts its own, in place of its words; /api/signals gives `items` beside `unread`, by the same rules as its list. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2552,6 +2552,7 @@ pub struct SignalRow {
|
||||
pub keywords: Vec<String>,
|
||||
pub description: Option<String>,
|
||||
pub icon: Option<String>,
|
||||
pub items: i64,
|
||||
pub unread: i64,
|
||||
}
|
||||
|
||||
@@ -2604,15 +2605,22 @@ impl Db {
|
||||
let mut a = Args::default();
|
||||
let user = a.p(user_id);
|
||||
let one = id.map(|i| format!("AND g.id = {}", a.p(i))).unwrap_or_default();
|
||||
// The items it shows, and of those the unread: what its list counts, by the same rules.
|
||||
let hits = |unread: &str| {
|
||||
format!(
|
||||
"(SELECT count(*) FROM signal_verdicts v
|
||||
JOIN entries e ON e.feed_id = v.feed_id AND e.guid = v.guid
|
||||
JOIN subscriptions s ON s.user_id = g.user_id AND s.feed_id = v.feed_id
|
||||
LEFT JOIN entry_state st ON st.user_id = g.user_id AND st.feed_id = v.feed_id AND st.guid = v.guid
|
||||
WHERE v.signal_id = g.id AND v.hit AND {unread} AND {})",
|
||||
not_hidden(&user)
|
||||
)
|
||||
};
|
||||
let sql = format!(
|
||||
"SELECT g.id, g.name, g.keywords, g.description, g.icon,
|
||||
(SELECT count(*) FROM signal_verdicts v
|
||||
JOIN entries e ON e.feed_id = v.feed_id AND e.guid = v.guid
|
||||
JOIN subscriptions s ON s.user_id = g.user_id AND s.feed_id = v.feed_id
|
||||
LEFT JOIN entry_state st ON st.user_id = g.user_id AND st.feed_id = v.feed_id AND st.guid = v.guid
|
||||
WHERE v.signal_id = g.id AND v.hit AND NOT coalesce(st.read, false) AND {}) AS unread
|
||||
"SELECT g.id, g.name, g.keywords, g.description, g.icon, {} AS items, {} AS unread
|
||||
FROM signals g WHERE g.user_id = {user} {one} ORDER BY lower(g.name), g.id",
|
||||
not_hidden(&user)
|
||||
hits("true"),
|
||||
hits("NOT coalesce(st.read, false)")
|
||||
);
|
||||
self.rows(&sql, a.0)
|
||||
.await?
|
||||
@@ -2624,6 +2632,7 @@ impl Db {
|
||||
keywords: keywords(r.try_get("", "keywords")?).unwrap_or_default(),
|
||||
description: r.try_get("", "description")?,
|
||||
icon: r.try_get("", "icon")?,
|
||||
items: r.try_get("", "items")?,
|
||||
unread: r.try_get("", "unread")?,
|
||||
})
|
||||
})
|
||||
@@ -3403,11 +3412,12 @@ mod tests {
|
||||
let page = db.signal_entries(1, f1, Filter::All, None, 0, 50, &order).await.unwrap();
|
||||
assert_eq!(page.iter().map(|e| e.guid.as_str()).collect::<Vec<_>>(), ["x"]);
|
||||
assert_eq!(db.signal_count(1, food, Filter::All, None).await.unwrap(), 1);
|
||||
assert_eq!(db.signals(1).await.unwrap().iter().map(|s| s.unread).collect::<Vec<_>>(), [1, 1]);
|
||||
assert_eq!(db.signals(1).await.unwrap().iter().map(|s| (s.items, s.unread)).collect::<Vec<_>>(), [(1, 1), (1, 1)]);
|
||||
db.exec_for_test("INSERT INTO entry_state (user_id, feed_id, guid, read, flagged, position) VALUES (1,'f','x',true,false,0)")
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(db.signal(1, f1).await.unwrap().unwrap().unread, 0, "read in its feed is read in the Signal");
|
||||
let f = db.signal(1, f1).await.unwrap().unwrap();
|
||||
assert_eq!((f.items, f.unread), (1, 0), "read in its feed is read in the Signal, and still one of its items");
|
||||
|
||||
assert!(db.signal(2, f1).await.unwrap().is_none(), "someone else's Signal is not found");
|
||||
assert!(!db.set_signal(2, f1, SignalChange { name: Some("mine"), ..Default::default() }).await.unwrap());
|
||||
|
||||
Reference in New Issue
Block a user