diff --git a/CHANGELOG.md b/CHANGELOG.md index 25880f9..340baa6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,10 @@ # Changelog -## 0.5.2 (Unreleased) +## 0.5.2 (2025-01-28) + +- Logging in no longer replaces your document. Instead, it asks if you'd like to merge or replace. + +This release is available as a container image at `ghcr.io/bytes-zone/beeps:v0.5.2`. ## 0.5.1 (2025-01-28) diff --git a/Cargo.lock b/Cargo.lock index c57c217..4f6e817 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -427,7 +427,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "beeps" -version = "0.5.1" +version = "0.5.2" dependencies = [ "beeps_core", "chrono", @@ -449,7 +449,7 @@ dependencies = [ [[package]] name = "beeps-server" -version = "0.5.1" +version = "0.5.2" dependencies = [ "argon2", "axum", @@ -470,7 +470,7 @@ dependencies = [ [[package]] name = "beeps_core" -version = "0.5.1" +version = "0.5.2" dependencies = [ "chrono", "proptest", @@ -568,7 +568,7 @@ dependencies = [ [[package]] name = "browser" -version = "0.5.1" +version = "0.5.2" dependencies = [ "beeps_core", "chrono", diff --git a/beeps-server/Cargo.toml b/beeps-server/Cargo.toml index 7ee1bf0..6b9e3fc 100644 --- a/beeps-server/Cargo.toml +++ b/beeps-server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "beeps-server" -version = "0.5.1" +version = "0.5.2" edition = "2021" [dependencies] diff --git a/beeps/Cargo.toml b/beeps/Cargo.toml index 7103741..f008909 100644 --- a/beeps/Cargo.toml +++ b/beeps/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "beeps" -version = "0.5.1" +version = "0.5.2" edition = "2021" [lints] diff --git a/beeps/src/app.rs b/beeps/src/app.rs index b062488..12945eb 100644 --- a/beeps/src/app.rs +++ b/beeps/src/app.rs @@ -16,7 +16,7 @@ use popover::{AuthIntent, Popover}; use crate::config::Config; use beeps_core::{ sync::{login, register, Client}, - NodeId, Replica, + Document, NodeId, Replica, }; use chrono::{DateTime, Local, Utc}; use crossterm::event::{Event, KeyCode, KeyEvent, KeyEventKind}; @@ -42,7 +42,12 @@ pub struct App { /// If we're replacing the entire replica on the next sync (for example when /// initially logging in.) - replace_on_next_sync: bool, + in_first_sync: bool, + + /// The document we got on our first sync. We keep this separate to decide + /// whether to replace our current document with this or merge them + /// together. + first_sync_document: Option, /// State of the pings table table_state: TableState, @@ -89,7 +94,8 @@ impl App { Ok(Self { status_line: Some("Loaded replica".to_string()), replica, - replace_on_next_sync: false, + in_first_sync: false, + first_sync_document: None, client: auth, last_sync: None, table_state: TableState::new().with_selected(0), @@ -104,7 +110,8 @@ impl App { status_line: None, replica: Replica::new(NodeId::random()), client: auth, - replace_on_next_sync: false, + in_first_sync: false, + first_sync_document: None, last_sync: None, table_state: TableState::new().with_selected(0), popover: None, @@ -253,7 +260,7 @@ impl App { } Action::LoggedIn(client) => { self.client = Some(client.clone()); - self.replace_on_next_sync = true; + self.in_first_sync = true; vec![ Effect::SaveSyncClientAuth(client.clone()), @@ -273,12 +280,12 @@ impl App { Action::Pulled(resp) => { self.status_line = Some("Got a new doc from the server".to_string()); - if self.replace_on_next_sync { - self.replica.replace_doc(resp.document); - self.replace_on_next_sync = false; + if self.in_first_sync { + self.first_sync_document = Some(resp.document); + self.popover = Some(Popover::ConfirmReplaceOrMerge); } else { self.replica.merge(resp.document); - } + }; vec![] } @@ -355,6 +362,25 @@ impl App { } _ => auth.handle_event(key), }, + Some(Popover::ConfirmReplaceOrMerge) => match key.code { + KeyCode::Char('r') => { + self.dismiss_popover(); + self.in_first_sync = false; + if let Some(document) = self.first_sync_document.take() { + self.replica.replace_doc(document); + effects.push(Effect::SaveReplica(self.replica.clone())); + } + } + KeyCode::Char('m') => { + self.dismiss_popover(); + self.in_first_sync = false; + if let Some(document) = self.first_sync_document.take() { + self.replica.merge(document); + effects.push(Effect::SaveReplica(self.replica.clone())); + } + } + _ => (), + }, } effects diff --git a/beeps/src/app/popover.rs b/beeps/src/app/popover.rs index 75acc49..d62d7c4 100644 --- a/beeps/src/app/popover.rs +++ b/beeps/src/app/popover.rs @@ -19,6 +19,9 @@ pub enum Popover { /// Register with the server Authenticating(auth_form::AuthForm, AuthIntent), + + /// Confirm whether or not we want to replace the full sync information or merge it. + ConfirmReplaceOrMerge, } /// When we're working with an Authenticating popover, what do we intend to do @@ -103,6 +106,28 @@ impl Popover { )); } Popover::Authenticating(auth, _) => auth.render(body_area, frame), + Popover::ConfirmReplaceOrMerge => { + let popup_vert = Layout::vertical([Constraint::Percentage(50)]).flex(Flex::Center); + let popup_horiz = + Layout::horizontal([Constraint::Percentage(50)]).flex(Flex::Center); + + let [popup_area] = popup_vert.areas(body_area); + let [popup_area] = popup_horiz.areas(popup_area); + + let popup = Paragraph::new( + "You've successfully logged in! Do you want to replace your local data with the server's data, or merge local and remote data?\n\nPress 'r' to replace, or 'm' to merge.", + ) + .block( + Block::default() + .borders(Borders::ALL) + .title("Replace or Merge?") + .padding(Padding::horizontal(1)) + .border_style(Style::new().blue()), + ); + + frame.render_widget(Clear, popup_area); + frame.render_widget(popup, popup_area); + } } } } diff --git a/beeps_core/Cargo.toml b/beeps_core/Cargo.toml index 33f2431..158bb82 100644 --- a/beeps_core/Cargo.toml +++ b/beeps_core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "beeps_core" -version = "0.5.1" +version = "0.5.2" edition = "2021" [lints] diff --git a/browser/Cargo.toml b/browser/Cargo.toml index 7b4cea5..de5a277 100644 --- a/browser/Cargo.toml +++ b/browser/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "browser" -version = "0.5.1" +version = "0.5.2" edition = "2021" [lib]