Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
[WIP] bin/inbox: add chunked UI item creation
✗ CI failure Erik Kundt committed 6 months ago
commit f06dad54979a7c7889cf8af4670a1ce0f43b3b85
parent c66a399c8ae426654b22dda9351337cd9b25c0e0
1 failed (1 total) View logs
1 file changed +83 -55
modified bin/commands/inbox/list.rs
@@ -17,10 +17,10 @@ use ratatui::text::Text;
use ratatui::Viewport;

use radicle::identity::Project;
+
use radicle::node;
use radicle::node::notifications::NotificationId;
use radicle::prelude::RepoId;
-
use radicle::storage::ReadRepository;
-
use radicle::storage::ReadStorage;
+
use radicle::storage::{ReadRepository, ReadStorage};
use radicle::Profile;

use radicle_tui as tui;
@@ -50,6 +50,50 @@ use super::common::{Mode, RepositoryMode};

type Selection = tui::Selection<NotificationId>;

+
#[derive(Clone, Debug, Default)]
+
struct Notifications {
+
    inner: Vec<Notification>,
+
}
+

+
impl Notifications {
+
    fn sort(&mut self, context: &Context) {
+
        // Apply sorting
+
        match context.sort_by.field {
+
            "timestamp" => self.inner.sort_by(|a, b| a.timestamp.cmp(&b.timestamp)),
+
            "id" => self.inner.sort_by(|a, b| a.id.cmp(&b.id)),
+
            _ => {}
+
        }
+
        if context.sort_by.reverse {
+
            self.inner.reverse();
+
        }
+

+
        // Sort by project if all notifications are shown
+
        if let RepositoryMode::All = context.mode.repository() {
+
            self.inner.sort_by(|a, b| a.project.cmp(&b.project));
+
        }
+
    }
+

+
    pub fn inner(&self) -> &Vec<Notification> {
+
        &self.inner
+
    }
+
}
+

+
impl Iterator for Notifications {
+
    type Item = Notification;
+

+
    fn next(&mut self) -> Option<Self::Item> {
+
        self.inner.iter().next().cloned()
+
    }
+
}
+

+
impl From<Vec<Notification>> for Notifications {
+
    fn from(value: Vec<Notification>) -> Self {
+
        Self {
+
            inner: value.to_vec(),
+
        }
+
    }
+
}
+

#[derive(Clone, Debug)]
struct Worker {
    sender: UnboundedSender<Message>,
@@ -61,7 +105,7 @@ impl Worker {
        tokio::spawn(async move {
            let context = context.lock().unwrap();

-
            let mut notifications = match context.mode.repository() {
+
            let notifications = match context.mode.repository() {
                RepositoryMode::All => {
                    let mut repos = context.profile.storage.repositories()?;
                    repos.sort_by_key(|r| r.rid);
@@ -69,15 +113,7 @@ impl Worker {
                    let mut notifs = vec![];
                    for repo in repos {
                        let repo = context.profile.storage.repository(repo.rid)?;
-

-
                        let items = inbox::all(&repo, &context.profile)?
-
                            .iter()
-
                            .map(|notif| {
-
                                Notification::new(&context.profile, &context.project, &repo, notif)
-
                            })
-
                            .filter_map(|item| item.ok())
-
                            .flatten()
-
                            .collect::<Vec<_>>();
+
                        let items = inbox::all(&repo, &context.profile)?;

                        notifs.extend(items);
                    }
@@ -86,34 +122,11 @@ impl Worker {
                }
                RepositoryMode::Contextual => {
                    let repository = context.profile.storage.repository(context.rid)?;
-
                    let notifs = inbox::all(&repository, &context.profile)?;
-

-
                    notifs
-
                        .iter()
-
                        .map(|notif| {
-
                            Notification::new(
-
                                &context.profile,
-
                                &context.project,
-
                                &repository,
-
                                notif,
-
                            )
-
                        })
-
                        .filter_map(|item| item.ok())
-
                        .flatten()
-
                        .collect::<Vec<_>>()
+
                    inbox::all(&repository, &context.profile)?
                }
                RepositoryMode::ByRepo((rid, _)) => {
                    let repo = context.profile.storage.repository(*rid)?;
-
                    let notifs = inbox::all(&repo, &context.profile)?;
-

-
                    notifs
-
                        .iter()
-
                        .map(|notif| {
-
                            Notification::new(&context.profile, &context.project, &repo, notif)
-
                        })
-
                        .filter_map(|item| item.ok())
-
                        .flatten()
-
                        .collect::<Vec<_>>()
+
                    inbox::all(&repo, &context.profile)?
                }
            };

@@ -136,22 +149,26 @@ impl Worker {
                _ => context.mode.clone(),
            };

-
            // Apply sorting
-
            // match context.sort_by.field {
-
            //     "timestamp" => notifications.sort_by(|a, b| a.timestamp.cmp(&b.timestamp)),
-
            //     "id" => notifications.sort_by(|a, b| a.id.cmp(&b.id)),
-
            //     _ => {}
-
            // }
-
            // if context.sort_by.reverse {
-
            //     notifications.reverse();
-
            // }
-

-
            // Sort by project if all notifications are shown
-
            if let RepositoryMode::All = mode.repository() {
-
                notifications.sort_by(|a, b| a.project.cmp(&b.project));
-
            }
+
            let mut loaded_notifications = vec![];

-
            let _ = tx.send(Message::NotificationsLoaded(notifications));
+
            let chunks = notifications
+
                .chunks(10)
+
                .map(|c| c.to_vec())
+
                .collect::<Vec<Vec<_>>>();
+
            for chunk in chunks {
+
                loaded_notifications.extend(
+
                    chunk
+
                        .iter()
+
                        .map(|notif| {
+
                            let repo = context.profile.storage.repository(notif.repo)?;
+
                            Notification::new(&context.profile, &context.project, &repo, notif)
+
                        })
+
                        .filter_map(|item| item.ok())
+
                        .flatten()
+
                        .collect::<Vec<_>>(),
+
                );
+
                let _ = tx.send(Message::NotificationsLoaded(loaded_notifications.clone()));
+
            }

            anyhow::Ok(())
        });
@@ -180,7 +197,7 @@ pub enum AppPage {

#[derive(Clone, Debug)]
pub struct BrowserState {
-
    items: Vec<Notification>,
+
    items: Notifications,
    selected: Option<usize>,
    filter: NotificationFilter,
    search: BufferedValue<String>,
@@ -190,11 +207,16 @@ pub struct BrowserState {
impl BrowserState {
    pub fn notifications(&self) -> Vec<Notification> {
        self.items
+
            .inner()
            .iter()
            .filter(|patch| self.filter.matches(patch))
            .cloned()
            .collect()
    }
+

+
    pub fn sort(&mut self, context: &Context) {
+
        self.items.sort(context);
+
    }
}

#[derive(Clone, Debug)]
@@ -218,7 +240,7 @@ impl State {
        Ok(Self {
            pages: PageStack::new(vec![AppPage::Browse]),
            browser: BrowserState {
-
                items: vec![],
+
                items: Notifications::default(),
                selected: Some(0),
                filter: context.filter.clone(),
                search,
@@ -241,6 +263,7 @@ pub enum Message {
    UpdateSearch { value: String },
    ApplySearch,
    CloseSearch,
+
    ApplySorting,
    OpenHelp,
    LeavePage,
    ScrollHelp { state: TextViewState },
@@ -288,6 +311,11 @@ impl store::Update<Message> for State {

                None
            }
+
            Message::ApplySorting => {
+
                let context = self.context.lock().unwrap();
+
                self.browser.sort(&context);
+
                None
+
            }
            Message::OpenHelp => {
                self.pages.push(AppPage::Help);
                None
@@ -307,7 +335,7 @@ impl store::Update<Message> for State {
                None
            }
            Message::NotificationsLoaded(notifs) => {
-
                self.browser.items = notifs;
+
                self.browser.items = Notifications::from(notifs);
                None
            }
        }