mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 11:20:36 +08:00
Fix inbox pagination cursor and sorting
This commit is contained in:
@@ -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<AppState>,
|
||||
sqlite_service: tauri::State<Service<Sqlite>>,
|
||||
params: notification::RepoGroupParams,
|
||||
) -> Result<
|
||||
PaginatedQuery<BTreeMap<git::Qualified<'static>, Vec<notification::NotificationItem>>>,
|
||||
Error,
|
||||
> {
|
||||
) -> Result<PaginatedQuery<RepoGroupByItem>, 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::<BTreeMap<git::Qualified<'static>, Vec<notification::NotificationItem>>>();
|
||||
.collect::<RepoGroupByItem>();
|
||||
|
||||
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((
|
||||
|
||||
@@ -33,7 +33,8 @@ pub struct NotificationRow {
|
||||
pub new: Option<git::Oid>,
|
||||
}
|
||||
|
||||
pub type RepoGroup = std::collections::BTreeMap<git::Qualified<'static>, Vec<NotificationRow>>;
|
||||
pub type RepoGroup = Vec<(git::Qualified<'static>, Vec<NotificationRow>)>;
|
||||
pub type RepoGroupByItem = Vec<(git::Qualified<'static>, Vec<NotificationItem>)>;
|
||||
pub type CountByRepo = (identity::RepoId, usize);
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
||||
@@ -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<git::Qualified<'static>, Vec<NotificationRow>>,
|
||||
ListNotificationsError,
|
||||
> {
|
||||
fn repo_group(&self, params: RepoGroupParams) -> Result<RepoGroup, ListNotificationsError> {
|
||||
self.inbox.repo_group(params)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<git::Qualified<'static>, Vec<notification::NotificationRow>>,
|
||||
notification::ListNotificationsError,
|
||||
> {
|
||||
) -> Result<notification::RepoGroup, notification::ListNotificationsError> {
|
||||
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::<Result<
|
||||
BTreeMap<git::Qualified<'static>, Vec<notification::NotificationRow>>,
|
||||
notification::ListNotificationsError,
|
||||
>>()
|
||||
.collect::<Result<notification::RepoGroup, notification::ListNotificationsError>>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
clearByIds: (rid: string, ids: string[]) => Promise<void>;
|
||||
clearByRepo: (rid: string) => Promise<void>;
|
||||
repo: HomeInboxTab;
|
||||
items: Record<string, NotificationItem[]>;
|
||||
items: [string, NotificationItem[]][];
|
||||
more: boolean;
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
{/if}
|
||||
|
||||
<div class="container">
|
||||
{#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]}
|
||||
<NotificationTeaser
|
||||
{clearByIds}
|
||||
rid={repo.rid}
|
||||
|
||||
@@ -49,7 +49,7 @@ interface LoadedInboxRoute {
|
||||
string,
|
||||
{
|
||||
repo: HomeInboxTab;
|
||||
items: Record<string, NotificationItem[]>;
|
||||
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<Record<string, NotificationItem[]>>
|
||||
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<Record<string, NotificationItem[]>>
|
||||
PaginatedQuery<[string, NotificationItem[]][]>
|
||||
>("list_notifications", {
|
||||
params: {
|
||||
repo: rid,
|
||||
|
||||
+12
-11
@@ -25,7 +25,7 @@
|
||||
string,
|
||||
{
|
||||
repo: HomeInboxTab;
|
||||
items: Record<string, NotificationItem[]>;
|
||||
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<PaginatedQuery<Record<string, NotificationItem[]>>>(
|
||||
invoke<PaginatedQuery<[string, NotificationItem[]][]>>(
|
||||
"list_notifications",
|
||||
{
|
||||
params: {
|
||||
@@ -124,16 +124,17 @@
|
||||
|
||||
async function loadMoreContent() {
|
||||
if (more && activeTab) {
|
||||
const c = cursor ? cursor : 20;
|
||||
const p = await invoke<
|
||||
PaginatedQuery<Record<string, NotificationItem[]>>
|
||||
>("list_notifications", {
|
||||
params: {
|
||||
repo: activeTab.rid,
|
||||
skip: more ? c + 20 : c,
|
||||
take: 20,
|
||||
const c = cursor ? cursor : 0;
|
||||
const p = await invoke<PaginatedQuery<[string, NotificationItem[]][]>>(
|
||||
"list_notifications",
|
||||
{
|
||||
params: {
|
||||
repo: activeTab.rid,
|
||||
skip: more ? c + 20 : c,
|
||||
take: 20,
|
||||
},
|
||||
},
|
||||
});
|
||||
);
|
||||
|
||||
cursor = p.cursor;
|
||||
more = p.more;
|
||||
|
||||
Reference in New Issue
Block a user