mirror of
https://seed.radicle.dev/rad:z39mP9rQAaGmERfUMPULfPUi473tY.git
synced 2026-11-16 00:10:38 +08:00
refactor: Improve app context creation
This commit is contained in:
@@ -1,10 +1,17 @@
|
||||
use radicle_term as term;
|
||||
|
||||
use radicle::cob::issue::{Issue, IssueId};
|
||||
use radicle::cob::patch::{Patch, PatchId};
|
||||
use radicle::crypto::ssh::keystore::MemorySigner;
|
||||
use radicle::prelude::{Id, Project, Signer};
|
||||
use radicle::profile::env::RAD_PASSPHRASE;
|
||||
use radicle::Profile;
|
||||
|
||||
use radicle::storage::git::Repository;
|
||||
use radicle::storage::ReadStorage;
|
||||
|
||||
use term::{passphrase, spinner};
|
||||
|
||||
pub struct Context {
|
||||
profile: Profile,
|
||||
id: Id,
|
||||
@@ -16,12 +23,22 @@ pub struct Context {
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn new(profile: Profile, id: Id, project: Project, signer: Box<dyn Signer>) -> Self {
|
||||
pub fn new(id: Id) -> Result<Self, anyhow::Error> {
|
||||
use anyhow::Context;
|
||||
|
||||
let profile = profile()?;
|
||||
let signer = signer(&profile)?;
|
||||
let payload = &profile
|
||||
.storage
|
||||
.get(signer.public_key(), id)?
|
||||
.context("No project with such `id` exists")?;
|
||||
let project = payload.project()?;
|
||||
|
||||
let repository = profile.storage.repository(id).unwrap();
|
||||
let issues = crate::cob::issue::all(&repository).unwrap_or_default();
|
||||
let patches = crate::cob::patch::all(&repository).unwrap_or_default();
|
||||
|
||||
Self {
|
||||
Ok(Self {
|
||||
id,
|
||||
profile,
|
||||
project,
|
||||
@@ -29,7 +46,7 @@ impl Context {
|
||||
issues,
|
||||
patches,
|
||||
signer,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn profile(&self) -> &Profile {
|
||||
@@ -66,3 +83,27 @@ impl Context {
|
||||
self.patches = crate::cob::patch::all(&self.repository).unwrap_or_default();
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default profile. Fails if there is no profile.
|
||||
fn profile() -> Result<Profile, anyhow::Error> {
|
||||
match Profile::load() {
|
||||
Ok(profile) => Ok(profile),
|
||||
Err(_) => Err(anyhow::anyhow!(
|
||||
"Could not load radicle profile. To setup your radicle profile, run `rad auth`."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the signer. First we try getting it from ssh-agent, otherwise we prompt the user.
|
||||
fn signer(profile: &Profile) -> anyhow::Result<Box<dyn Signer>> {
|
||||
if let Ok(signer) = profile.signer() {
|
||||
return Ok(signer);
|
||||
}
|
||||
let passphrase = passphrase(RAD_PASSPHRASE)?;
|
||||
let spinner = spinner("Unsealing key...");
|
||||
let signer = MemorySigner::load(&profile.keystore, Some(passphrase))?;
|
||||
|
||||
spinner.finish();
|
||||
|
||||
Ok(signer.boxed())
|
||||
}
|
||||
+3
-6
@@ -5,9 +5,6 @@ mod ui;
|
||||
use anyhow::Result;
|
||||
|
||||
use radicle::cob::issue::IssueId;
|
||||
use radicle::identity::{Id, Project};
|
||||
use radicle::prelude::Signer;
|
||||
use radicle::profile::Profile;
|
||||
|
||||
use tuirealm::application::PollStrategy;
|
||||
use tuirealm::{Application, Frame, NoUserEvent, Sub, SubClause};
|
||||
@@ -15,7 +12,7 @@ use tuirealm::{Application, Frame, NoUserEvent, Sub, SubClause};
|
||||
use radicle_tui as tui;
|
||||
|
||||
use tui::cob;
|
||||
use tui::ui::context::Context;
|
||||
use tui::context::Context;
|
||||
use tui::ui::subscription;
|
||||
use tui::ui::theme::{self, Theme};
|
||||
use tui::PageStack;
|
||||
@@ -105,9 +102,9 @@ pub struct App {
|
||||
/// Creates a new application using a tui-realm-application, mounts all
|
||||
/// components and sets focus to a default one.
|
||||
impl App {
|
||||
pub fn new(profile: Profile, id: Id, project: Project, signer: Box<dyn Signer>) -> Self {
|
||||
pub fn new(context: Context) -> Self {
|
||||
Self {
|
||||
context: Context::new(profile, id, project, signer),
|
||||
context,
|
||||
pages: PageStack::default(),
|
||||
theme: theme::default_dark(),
|
||||
quit: false,
|
||||
|
||||
@@ -9,7 +9,7 @@ use tuirealm::{AttrValue, Attribute, Frame, NoUserEvent, State, StateValue, Sub,
|
||||
use radicle_tui as tui;
|
||||
|
||||
use tui::cob;
|
||||
use tui::ui::context::Context;
|
||||
use tui::context::Context;
|
||||
use tui::ui::layout;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::widget::context::{Progress, Shortcuts};
|
||||
|
||||
+1
-1
@@ -10,9 +10,9 @@ use tuirealm::{AttrValue, Attribute, Frame, MockComponent, Props, State};
|
||||
|
||||
use radicle_tui as tui;
|
||||
|
||||
use tui::context::Context;
|
||||
use tui::ui::cob;
|
||||
use tui::ui::cob::IssueItem;
|
||||
use tui::ui::context::Context;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
|
||||
+11
-42
@@ -1,20 +1,19 @@
|
||||
mod app;
|
||||
|
||||
use std::process;
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use anyhow::anyhow;
|
||||
|
||||
use radicle::profile;
|
||||
|
||||
use log::info;
|
||||
use log::LevelFilter;
|
||||
|
||||
use radicle::profile;
|
||||
use radicle::{
|
||||
crypto::ssh::keystore::MemorySigner, prelude::Signer, profile::env::RAD_PASSPHRASE, Profile,
|
||||
};
|
||||
use radicle_term as term;
|
||||
use radicle_tui::Window;
|
||||
use radicle_tui as tui;
|
||||
|
||||
use radicle::storage::ReadStorage;
|
||||
use term::{passphrase, spinner};
|
||||
|
||||
mod app;
|
||||
use tui::context;
|
||||
use tui::Window;
|
||||
|
||||
pub const NAME: &str = "rad-issue-tui";
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
@@ -59,42 +58,12 @@ impl Options {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default profile. Fails if there is no profile.
|
||||
pub fn profile() -> Result<Profile, anyhow::Error> {
|
||||
match Profile::load() {
|
||||
Ok(profile) => Ok(profile),
|
||||
Err(_) => Err(anyhow::anyhow!(
|
||||
"Could not load radicle profile. To setup your radicle profile, run `rad auth`."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the signer. First we try getting it from ssh-agent, otherwise we prompt the user.
|
||||
pub fn signer(profile: &Profile) -> anyhow::Result<Box<dyn Signer>> {
|
||||
if let Ok(signer) = profile.signer() {
|
||||
return Ok(signer);
|
||||
}
|
||||
let passphrase = passphrase(RAD_PASSPHRASE)?;
|
||||
let spinner = spinner("Unsealing key...");
|
||||
let signer = MemorySigner::load(&profile.keystore, Some(passphrase))?;
|
||||
|
||||
spinner.finish();
|
||||
|
||||
Ok(signer.boxed())
|
||||
}
|
||||
|
||||
fn execute() -> anyhow::Result<()> {
|
||||
let _ = Options::from_env()?;
|
||||
|
||||
let (_, id) = radicle::rad::cwd()
|
||||
.map_err(|_| anyhow!("this command must be run in the context of a project"))?;
|
||||
let profile = profile()?;
|
||||
let signer = signer(&profile)?;
|
||||
let payload = &profile
|
||||
.storage
|
||||
.get(signer.public_key(), id)?
|
||||
.context("No project with such `id` exists")?;
|
||||
let project = payload.project()?;
|
||||
let context = context::Context::new(id)?;
|
||||
|
||||
let logfile = format!(
|
||||
"{}/rad-issue-tui.log",
|
||||
@@ -104,7 +73,7 @@ fn execute() -> anyhow::Result<()> {
|
||||
info!("Launching window...");
|
||||
|
||||
let mut window = Window::default();
|
||||
window.run(&mut app::App::new(profile, id, project, signer), 1000 / FPS)?;
|
||||
window.run(&mut app::App::new(context), 1000 / FPS)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
+2
-1
@@ -9,9 +9,10 @@ use tuirealm::Frame;
|
||||
use tuirealm::{Application, EventListenerCfg, NoUserEvent};
|
||||
|
||||
pub mod cob;
|
||||
pub mod context;
|
||||
pub mod ui;
|
||||
|
||||
use ui::context::Context;
|
||||
use context::Context;
|
||||
use ui::theme::Theme;
|
||||
|
||||
/// Trait that must be implemented by client applications in order to be run
|
||||
|
||||
+4
-6
@@ -7,16 +7,14 @@ use std::hash::Hash;
|
||||
use anyhow::Result;
|
||||
|
||||
use radicle::cob::patch::PatchId;
|
||||
use radicle::identity::{Id, Project};
|
||||
use radicle::prelude::Signer;
|
||||
use radicle::profile::Profile;
|
||||
|
||||
use tuirealm::application::PollStrategy;
|
||||
use tuirealm::{Application, Frame, NoUserEvent, Sub, SubClause};
|
||||
|
||||
use radicle_tui as tui;
|
||||
|
||||
use radicle_tui::cob;
|
||||
use radicle_tui::ui::context::Context;
|
||||
use radicle_tui::context::Context;
|
||||
use radicle_tui::ui::subscription;
|
||||
use radicle_tui::ui::theme::{self, Theme};
|
||||
use radicle_tui::PageStack;
|
||||
@@ -88,9 +86,9 @@ pub struct App {
|
||||
/// Creates a new application using a tui-realm-application, mounts all
|
||||
/// components and sets focus to a default one.
|
||||
impl App {
|
||||
pub fn new(profile: Profile, id: Id, project: Project, signer: Box<dyn Signer>) -> Self {
|
||||
pub fn new(context: Context) -> Self {
|
||||
Self {
|
||||
context: Context::new(profile, id, project, signer),
|
||||
context,
|
||||
pages: PageStack::default(),
|
||||
theme: theme::default_dark(),
|
||||
quit: false,
|
||||
|
||||
@@ -8,7 +8,7 @@ use tuirealm::{Frame, NoUserEvent, State, StateValue, Sub, SubClause};
|
||||
|
||||
use radicle_tui as tui;
|
||||
|
||||
use tui::ui::context::Context;
|
||||
use tui::context::Context;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::widget::context::{Progress, Shortcuts};
|
||||
use tui::ui::widget::Widget;
|
||||
|
||||
+1
-1
@@ -6,9 +6,9 @@ use tuirealm::{AttrValue, Attribute, Frame, MockComponent, Props, State};
|
||||
|
||||
use radicle_tui as tui;
|
||||
|
||||
use tui::context::Context;
|
||||
use tui::ui::cob;
|
||||
use tui::ui::cob::PatchItem;
|
||||
use tui::ui::context::Context;
|
||||
use tui::ui::layout;
|
||||
use tui::ui::theme::Theme;
|
||||
use tui::ui::widget::{Widget, WidgetComponent};
|
||||
|
||||
+12
-43
@@ -1,20 +1,19 @@
|
||||
mod app;
|
||||
|
||||
use std::process;
|
||||
|
||||
use anyhow::{anyhow, Context};
|
||||
use anyhow::anyhow;
|
||||
|
||||
use radicle::profile;
|
||||
|
||||
use log::info;
|
||||
use log::LevelFilter;
|
||||
|
||||
use radicle::profile;
|
||||
use radicle::{
|
||||
crypto::ssh::keystore::MemorySigner, prelude::Signer, profile::env::RAD_PASSPHRASE, Profile,
|
||||
};
|
||||
use radicle_term as term;
|
||||
use radicle_tui::Window;
|
||||
use radicle_tui as tui;
|
||||
|
||||
use radicle::storage::ReadStorage;
|
||||
use term::{passphrase, spinner};
|
||||
|
||||
mod app;
|
||||
use tui::context;
|
||||
use tui::Window;
|
||||
|
||||
pub const NAME: &str = "rad-patch-tui";
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
@@ -24,7 +23,7 @@ pub const FPS: u64 = 60;
|
||||
pub const HELP: &str = r#"
|
||||
Usage
|
||||
|
||||
rad-patch-tui [<option>...]
|
||||
rad-patch-tui [<option>...]
|
||||
|
||||
Options
|
||||
|
||||
@@ -59,42 +58,12 @@ impl Options {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default profile. Fails if there is no profile.
|
||||
pub fn profile() -> Result<Profile, anyhow::Error> {
|
||||
match Profile::load() {
|
||||
Ok(profile) => Ok(profile),
|
||||
Err(_) => Err(anyhow::anyhow!(
|
||||
"Could not load radicle profile. To setup your radicle profile, run `rad auth`."
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the signer. First we try getting it from ssh-agent, otherwise we prompt the user.
|
||||
pub fn signer(profile: &Profile) -> anyhow::Result<Box<dyn Signer>> {
|
||||
if let Ok(signer) = profile.signer() {
|
||||
return Ok(signer);
|
||||
}
|
||||
let passphrase = passphrase(RAD_PASSPHRASE)?;
|
||||
let spinner = spinner("Unsealing key...");
|
||||
let signer = MemorySigner::load(&profile.keystore, Some(passphrase))?;
|
||||
|
||||
spinner.finish();
|
||||
|
||||
Ok(signer.boxed())
|
||||
}
|
||||
|
||||
fn execute() -> anyhow::Result<()> {
|
||||
let _ = Options::from_env()?;
|
||||
|
||||
let (_, id) = radicle::rad::cwd()
|
||||
.map_err(|_| anyhow!("this command must be run in the context of a project"))?;
|
||||
let profile = profile()?;
|
||||
let signer = signer(&profile)?;
|
||||
let payload = &profile
|
||||
.storage
|
||||
.get(signer.public_key(), id)?
|
||||
.context("No project with such `id` exists")?;
|
||||
let project = payload.project()?;
|
||||
let context = context::Context::new(id)?;
|
||||
|
||||
let logfile = format!(
|
||||
"{}/rad-patch-tui.log",
|
||||
@@ -104,7 +73,7 @@ fn execute() -> anyhow::Result<()> {
|
||||
info!("Launching window...");
|
||||
|
||||
let mut window = Window::default();
|
||||
window.run(&mut app::App::new(profile, id, project, signer), 1000 / FPS)?;
|
||||
window.run(&mut app::App::new(context), 1000 / FPS)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
pub mod cob;
|
||||
pub mod context;
|
||||
pub mod ext;
|
||||
pub mod layout;
|
||||
pub mod state;
|
||||
@@ -20,7 +19,7 @@ use widget::list::{ColumnWidth, Property, PropertyList, PropertyTable};
|
||||
|
||||
use widget::Widget;
|
||||
|
||||
use crate::ui::context::Context;
|
||||
use super::context::Context;
|
||||
use crate::ui::theme::Theme;
|
||||
|
||||
pub fn global_listener() -> Widget<GlobalListener> {
|
||||
|
||||
Reference in New Issue
Block a user