diff --git a/crates/radicle-tauri/src/commands/inbox.rs b/crates/radicle-tauri/src/commands/inbox.rs index 75fd6e903..44b817398 100644 --- a/crates/radicle-tauri/src/commands/inbox.rs +++ b/crates/radicle-tauri/src/commands/inbox.rs @@ -1,14 +1,13 @@ use std::collections::BTreeMap; -use radicle::identity::DocAt; +use radicle::identity; use radicle::issue::cache::Issues; use radicle::node; use radicle::patch::cache::Patches; use radicle::storage::{ReadRepository, ReadStorage}; -use radicle::{git, identity}; use radicle_types::cobs::PaginatedQuery; -use radicle_types::domain::inbox::models::notification; +use radicle_types::domain::inbox::models::notification::{self, RepoGroupByItem}; use radicle_types::domain::inbox::service::Service; use radicle_types::domain::inbox::traits::InboxService; use radicle_types::error::Error; @@ -20,10 +19,7 @@ pub fn list_notifications( ctx: tauri::State, sqlite_service: tauri::State>, params: notification::RepoGroupParams, -) -> Result< - PaginatedQuery, Vec>>, - Error, -> { +) -> Result, Error> { let profile = &ctx.profile; let aliases = profile.aliases(); let cursor = params.skip.unwrap_or(0); @@ -127,7 +123,7 @@ pub fn list_notifications( (qualified, items) }) .filter(|(_, v)| !v.is_empty()) - .collect::, Vec>>(); + .collect::(); Ok(PaginatedQuery { cursor, @@ -147,7 +143,7 @@ pub fn count_notifications_by_repo( .filter_map(|s| { let (rid, count) = s.ok()?; let repo = profile.storage.repository(rid).ok()?; - let DocAt { doc, .. } = repo.identity_doc().ok()?; + let identity::DocAt { doc, .. } = repo.identity_doc().ok()?; let project = doc.project().ok()?; Some(( diff --git a/crates/radicle-types/src/domain/inbox/models/notification.rs b/crates/radicle-types/src/domain/inbox/models/notification.rs index 4062c680f..2cf1d1db6 100644 --- a/crates/radicle-types/src/domain/inbox/models/notification.rs +++ b/crates/radicle-types/src/domain/inbox/models/notification.rs @@ -33,7 +33,8 @@ pub struct NotificationRow { pub new: Option, } -pub type RepoGroup = std::collections::BTreeMap, Vec>; +pub type RepoGroup = Vec<(git::Qualified<'static>, Vec)>; +pub type RepoGroupByItem = Vec<(git::Qualified<'static>, Vec)>; pub type CountByRepo = (identity::RepoId, usize); #[derive(Clone, Debug)] diff --git a/crates/radicle-types/src/domain/inbox/service.rs b/crates/radicle-types/src/domain/inbox/service.rs index f7749bd1b..dd0c960d0 100644 --- a/crates/radicle-types/src/domain/inbox/service.rs +++ b/crates/radicle-types/src/domain/inbox/service.rs @@ -1,7 +1,5 @@ -use radicle::git; - use crate::domain::inbox::models::notification::{ - CountByRepo, ListNotificationsError, NotificationRow, RepoGroupParams, + CountByRepo, ListNotificationsError, RepoGroup, RepoGroupParams, }; use crate::domain::inbox::traits::{InboxService, InboxStorage}; @@ -35,13 +33,7 @@ where self.inbox.counts_by_repo() } - fn repo_group( - &self, - params: RepoGroupParams, - ) -> Result< - std::collections::BTreeMap, Vec>, - ListNotificationsError, - > { + fn repo_group(&self, params: RepoGroupParams) -> Result { self.inbox.repo_group(params) } } diff --git a/crates/radicle-types/src/outbound/sqlite.rs b/crates/radicle-types/src/outbound/sqlite.rs index 9cb9aa4c5..f7f005daf 100644 --- a/crates/radicle-types/src/outbound/sqlite.rs +++ b/crates/radicle-types/src/outbound/sqlite.rs @@ -1,4 +1,3 @@ -use std::collections::BTreeMap; use std::path::Path; use std::str::FromStr; use std::sync::Arc; @@ -137,17 +136,24 @@ impl InboxStorage for Sqlite { fn repo_group( &self, params: notification::RepoGroupParams, - ) -> Result< - std::collections::BTreeMap, Vec>, - notification::ListNotificationsError, - > { + ) -> Result { let mut stmt = self.db.prepare( - "SELECT ref, substr(ref, 66) ref_without_namespace, json_group_array(json_object('row_id', rowid, 'timestamp', timestamp, 'remote', substr(ref, 17, 48), 'old', old, 'new', new)) as value - FROM 'repository-notifications' - WHERE repo = ? - GROUP BY ref_without_namespace - ORDER BY timestamp DESC" - )?; + "SELECT ref, substr(ref, 66) ref_without_namespace, + json_group_array( + json_object( + 'row_id', rowid, + 'timestamp', timestamp, + 'remote', substr(ref, 17, 48), + 'old', old, + 'new', new + ) + ) as value, + MAX(timestamp) AS latest_timestamp + FROM 'repository-notifications' + WHERE repo = ? + GROUP BY ref_without_namespace + ORDER BY latest_timestamp DESC", + )?; stmt.bind((1, ¶ms.repo))?; stmt.into_iter() @@ -160,9 +166,6 @@ impl InboxStorage for Sqlite { Ok((reference.to_owned(), items)) }) - .collect::, Vec>, - notification::ListNotificationsError, - >>() + .collect::>() } } diff --git a/src/components/RepoNotifications.svelte b/src/components/RepoNotifications.svelte index 905c80976..bca1cce7e 100644 --- a/src/components/RepoNotifications.svelte +++ b/src/components/RepoNotifications.svelte @@ -13,7 +13,7 @@ clearByIds: (rid: string, ids: string[]) => Promise; clearByRepo: (rid: string) => Promise; repo: HomeInboxTab; - items: Record; + items: [string, NotificationItem[]][]; more: boolean; } @@ -58,7 +58,7 @@ {/if}
- {#each Object.entries(items).sort((a, b) => b[1][0].timestamp - a[1][0].timestamp) as [_, notificationItems]} + {#each items.sort((a, b) => b[1][0].timestamp - a[1][0].timestamp) as [_, notificationItems]} ; + items: [string, NotificationItem[]][]; pagination: { cursor: number; more: boolean }; } >; @@ -115,7 +115,7 @@ export async function loadRoute( new SvelteMap(); if (route.activeTab) { const items = await invoke< - PaginatedQuery> + PaginatedQuery<[string, NotificationItem[]][]> >("list_notifications", { params: { repo: route.activeTab.rid, @@ -129,7 +129,7 @@ export async function loadRoute( } else { for (const [rid, item] of notificationCount) { const result = await invoke< - PaginatedQuery> + PaginatedQuery<[string, NotificationItem[]][]> >("list_notifications", { params: { repo: rid, diff --git a/src/views/home/Inbox.svelte b/src/views/home/Inbox.svelte index 1af0d32cb..02b8d2f77 100644 --- a/src/views/home/Inbox.svelte +++ b/src/views/home/Inbox.svelte @@ -25,7 +25,7 @@ string, { repo: HomeInboxTab; - items: Record; + items: [string, NotificationItem[]][]; pagination: { cursor: number; more: boolean }; } >; @@ -95,7 +95,7 @@ async function reload(rids: string[]) { for (const rid of rids) { const [n, count] = await Promise.all([ - invoke>>( + invoke>( "list_notifications", { params: { @@ -124,16 +124,17 @@ async function loadMoreContent() { if (more && activeTab) { - const c = cursor ? cursor : 20; - const p = await invoke< - PaginatedQuery> - >("list_notifications", { - params: { - repo: activeTab.rid, - skip: more ? c + 20 : c, - take: 20, + const c = cursor ? cursor : 0; + const p = await invoke>( + "list_notifications", + { + params: { + repo: activeTab.rid, + skip: more ? c + 20 : c, + take: 20, + }, }, - }); + ); cursor = p.cursor; more = p.more;