Implement status messages
This commit is contained in:
parent
890cb0be5e
commit
c1882e50df
55
src/app.rs
55
src/app.rs
@ -28,6 +28,19 @@ pub enum SnowballingStep {
|
|||||||
Forward,
|
Forward,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Clone)]
|
||||||
|
pub enum StatusMessage {
|
||||||
|
Info(String),
|
||||||
|
Warning(String),
|
||||||
|
Error(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for StatusMessage {
|
||||||
|
fn default() -> Self {
|
||||||
|
StatusMessage::Info("".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToString for SnowballingStep {
|
impl ToString for SnowballingStep {
|
||||||
fn to_string(&self) -> String {
|
fn to_string(&self) -> String {
|
||||||
match self {
|
match self {
|
||||||
@ -104,7 +117,8 @@ pub struct App {
|
|||||||
|
|
||||||
pub snowballing_step: SnowballingStep,
|
pub snowballing_step: SnowballingStep,
|
||||||
|
|
||||||
pub status_message: String,
|
#[serde(skip)]
|
||||||
|
pub status_message: StatusMessage,
|
||||||
|
|
||||||
#[serde(skip)]
|
#[serde(skip)]
|
||||||
pub should_quit: bool,
|
pub should_quit: bool,
|
||||||
@ -117,7 +131,6 @@ pub struct App {
|
|||||||
// TODO: Implement export of included papers into zotero (Use RIS format somehow)
|
// TODO: Implement export of included papers into zotero (Use RIS format somehow)
|
||||||
// TODO: Log everything relevant
|
// TODO: Log everything relevant
|
||||||
impl App {
|
impl App {
|
||||||
// TODO: Show error somehow
|
|
||||||
pub async fn add_seed_paper(&mut self, api_link: &String) {
|
pub async fn add_seed_paper(&mut self, api_link: &String) {
|
||||||
let publ =
|
let publ =
|
||||||
get_publication_by_id(api_link, "an.tsouchlos@gmail.com").await;
|
get_publication_by_id(api_link, "an.tsouchlos@gmail.com").await;
|
||||||
@ -129,10 +142,18 @@ impl App {
|
|||||||
"Failed to get publication metadata using OpenAlex API: {}",
|
"Failed to get publication metadata using OpenAlex API: {}",
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
|
self.set_status_message(StatusMessage::Error(format!(
|
||||||
|
"Failed to get publication metadata using OpenAlex API: {}",
|
||||||
|
err
|
||||||
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_status_message(&mut self, s: StatusMessage) {
|
||||||
|
self.status_message = s;
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn handle_key(&mut self, key: KeyCode) {
|
pub async fn handle_key(&mut self, key: KeyCode) {
|
||||||
if KeyCode::Esc == key {
|
if KeyCode::Esc == key {
|
||||||
self.should_quit = true;
|
self.should_quit = true;
|
||||||
@ -164,7 +185,11 @@ impl App {
|
|||||||
"The next snowballing step can only be initiated \
|
"The next snowballing step can only be initiated \
|
||||||
after screening all pending publications"
|
after screening all pending publications"
|
||||||
);
|
);
|
||||||
// TODO: Show warning/error somehow
|
self.set_status_message(StatusMessage::Warning(
|
||||||
|
"The next snowballing step can only be initiated \
|
||||||
|
after screening all pending publications"
|
||||||
|
.to_string(),
|
||||||
|
));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -173,13 +198,21 @@ impl App {
|
|||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
}
|
}
|
||||||
SnowballingStep::Backward => {
|
SnowballingStep::Backward => {
|
||||||
for publication in &self.included_publications {
|
self.set_status_message(StatusMessage::Info(
|
||||||
|
"Fetching references...".to_string(),
|
||||||
|
));
|
||||||
|
|
||||||
|
// TODO: Find a way to not clone the publications
|
||||||
|
for publication in
|
||||||
|
self.included_publications.clone()
|
||||||
|
{
|
||||||
|
// TODO: In addition to the referenced_works do
|
||||||
|
// an API call for citations
|
||||||
for reference in &publication.referenced_works {
|
for reference in &publication.referenced_works {
|
||||||
let api_link = format!(
|
let api_link = format!(
|
||||||
"https://api.openalex.org/{}",
|
"https://api.openalex.org/{}",
|
||||||
&reference[21..]
|
&reference[21..]
|
||||||
);
|
);
|
||||||
// https://openalex.org/W2085881930
|
|
||||||
let publ = get_publication_by_id(
|
let publ = get_publication_by_id(
|
||||||
&api_link,
|
&api_link,
|
||||||
"an.tsouchlos@gmail.com",
|
"an.tsouchlos@gmail.com",
|
||||||
@ -190,7 +223,6 @@ impl App {
|
|||||||
Ok(publ) => {
|
Ok(publ) => {
|
||||||
self.pending_publications.push(publ)
|
self.pending_publications.push(publ)
|
||||||
}
|
}
|
||||||
// TODO: Show error somehow
|
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
warn!(
|
warn!(
|
||||||
"Failed to get publication\
|
"Failed to get publication\
|
||||||
@ -198,9 +230,20 @@ impl App {
|
|||||||
{}",
|
{}",
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
|
|
||||||
|
self.set_status_message(
|
||||||
|
StatusMessage::Error(format!(
|
||||||
|
"Failed to get publication\
|
||||||
|
metadata using OpenAlex API: \
|
||||||
|
{}",
|
||||||
|
err
|
||||||
|
)),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.set_status_message(StatusMessage::Info("Done".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -88,12 +88,12 @@ async fn main() {
|
|||||||
.init();
|
.init();
|
||||||
|
|
||||||
match run(&args).await {
|
match run(&args).await {
|
||||||
Ok(()) => info!("Application completed successfully"),
|
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("Application error: {}", e);
|
error!("Application error: {}", e);
|
||||||
print!("{e:?}");
|
print!("{e:?}");
|
||||||
std::process::exit(1);
|
std::process::exit(1);
|
||||||
}
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,14 +5,14 @@ use serde::{Deserialize, Serialize};
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use unicode_general_category::{GeneralCategory, get_general_category};
|
use unicode_general_category::{GeneralCategory, get_general_category};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Authorship {
|
pub struct Authorship {
|
||||||
pub author_position: String,
|
pub author_position: String,
|
||||||
pub raw_author_name: String,
|
pub raw_author_name: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle duplicates by having vectors of ids
|
// TODO: Handle duplicates by having vectors of ids
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Publication {
|
pub struct Publication {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub display_name: Option<String>,
|
pub display_name: Option<String>,
|
||||||
|
|||||||
24
src/ui.rs
24
src/ui.rs
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
app::{ActivePane, ActiveTab, App},
|
app::{ActivePane, ActiveTab, App, StatusMessage},
|
||||||
snowballing::Publication,
|
snowballing::Publication,
|
||||||
};
|
};
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
@ -20,7 +20,11 @@ pub fn draw(f: &mut Frame, app: &mut App) {
|
|||||||
fn draw_seeding_tab(f: &mut Frame, app: &mut App) {
|
fn draw_seeding_tab(f: &mut Frame, app: &mut App) {
|
||||||
let chunks = Layout::default()
|
let chunks = Layout::default()
|
||||||
.direction(Direction::Vertical)
|
.direction(Direction::Vertical)
|
||||||
.constraints([Constraint::Min(3), Constraint::Length(3)])
|
.constraints([
|
||||||
|
Constraint::Min(3),
|
||||||
|
Constraint::Length(3),
|
||||||
|
Constraint::Length(1),
|
||||||
|
])
|
||||||
.split(f.area());
|
.split(f.area());
|
||||||
|
|
||||||
// Included publication list
|
// Included publication list
|
||||||
@ -62,6 +66,10 @@ fn draw_seeding_tab(f: &mut Frame, app: &mut App) {
|
|||||||
.block(Block::bordered().title("Input"));
|
.block(Block::bordered().title("Input"));
|
||||||
|
|
||||||
f.render_widget(input, chunks[1]);
|
f.render_widget(input, chunks[1]);
|
||||||
|
|
||||||
|
// Status line
|
||||||
|
|
||||||
|
draw_status_line(f, app, chunks[2]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_snowballing_tab(f: &mut Frame, app: &mut App) {
|
fn draw_snowballing_tab(f: &mut Frame, app: &mut App) {
|
||||||
@ -322,8 +330,16 @@ fn draw_right_pane(frame: &mut Frame, app: &mut App, area: Rect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn draw_status_line(frame: &mut Frame, app: &App, area: Rect) {
|
fn draw_status_line(frame: &mut Frame, app: &App, area: Rect) {
|
||||||
let line = Paragraph::new(app.status_message.clone())
|
let line = Paragraph::new(Line::from(match app.status_message.clone() {
|
||||||
.style(Style::default().bg(Color::Rgb(60, 56, 54)));
|
StatusMessage::Info(s) => Span::raw(s),
|
||||||
|
StatusMessage::Warning(s) => {
|
||||||
|
Span::styled(s, Style::default().fg(Color::Yellow))
|
||||||
|
}
|
||||||
|
StatusMessage::Error(s) => {
|
||||||
|
Span::styled(s, Style::default().fg(Color::Red))
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
.style(Style::default().bg(Color::Rgb(60, 56, 54)));
|
||||||
|
|
||||||
frame.render_widget(line, area);
|
frame.render_widget(line, area);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user