rewrote TagList with a new behaviour

This commit is contained in:
Thomas Eppers 2021-10-22 17:23:37 +02:00
parent a82119f827
commit c9a8c637c4
5 changed files with 126 additions and 129 deletions

View File

@ -4,7 +4,7 @@ use crate::repo;
use chrono::DateTime; use chrono::DateTime;
use serde::Deserialize; use serde::Deserialize;
#[derive(Deserialize, Debug)] #[derive(Deserialize, Debug, Clone)]
struct ImageDetails { struct ImageDetails {
architecture: String, architecture: String,
// os: String, // os: String,
@ -17,7 +17,7 @@ impl fmt::Display for ImageDetails {
} }
} }
#[derive(Deserialize)] #[derive(Deserialize, Clone)]
pub struct Images { pub struct Images {
images: Vec<ImageDetails>, images: Vec<ImageDetails>,
#[serde(rename(deserialize = "name"))] #[serde(rename(deserialize = "name"))]
@ -29,9 +29,7 @@ pub struct Images {
pub struct Tags { pub struct Tags {
count: usize, count: usize,
#[serde(rename(deserialize = "next"))] #[serde(rename(deserialize = "next"))]
next_page: Option<String>, pub next_page: Option<String>,
#[serde(rename(deserialize = "previous"))]
prev_page: Option<String>,
pub results: Vec<Images>, pub results: Vec<Images>,
} }
@ -43,7 +41,6 @@ pub enum Error {
Converting(String), Converting(String),
/// invalid repos show a valid json with 0 tags /// invalid repos show a valid json with 0 tags
NoTagsFound, NoTagsFound,
NoPrevPage,
NoNextPage, NoNextPage,
} }
@ -53,7 +50,6 @@ impl fmt::Display for Error {
Error::Fetching(s) => write!(f, "Fetching error: {}", s), Error::Fetching(s) => write!(f, "Fetching error: {}", s),
Error::Converting(s) => write!(f, "Converting error: {}", s), Error::Converting(s) => write!(f, "Converting error: {}", s),
Error::NoNextPage => write!(f, "No next page available"), Error::NoNextPage => write!(f, "No next page available"),
Error::NoPrevPage => write!(f, "No previous page available"),
Error::NoTagsFound => write!(f, "Given Repo has 0 tags. Is it valid?"), Error::NoTagsFound => write!(f, "Given Repo has 0 tags. Is it valid?"),
} }
} }
@ -108,14 +104,6 @@ impl Tags {
None => Err(Error::NoNextPage), None => Err(Error::NoNextPage),
} }
} }
/// returns tags of previous page
pub fn prev_page(&self) -> Result<Self, Error> {
match &self.prev_page {
Some(url) => Self::with_url(url),
None => Err(Error::NoPrevPage),
}
}
} }
impl fmt::Display for Images { impl fmt::Display for Images {

View File

@ -44,7 +44,7 @@ impl Ui {
pub fn run(opt: &Opt) { pub fn run(opt: &Opt) {
let (repo_id, load_repo) = match &opt.repo { let (repo_id, load_repo) = match &opt.repo {
None => ( None => (
"enter a repository or select one from docker-compose.yml", "enter a repository here or select one from file widget",
false, false,
), ),
Some(repo) => (String::as_str(repo), true), Some(repo) => (String::as_str(repo), true),
@ -59,7 +59,7 @@ impl Ui {
}; };
if load_repo { if load_repo {
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
//setup tui //setup tui
@ -113,20 +113,12 @@ impl Ui {
}, },
Ok(Key::Ctrl('r')) => { Ok(Key::Ctrl('r')) => {
ui.repo.confirm(); ui.repo.confirm();
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
Ok(Key::Ctrl('n')) => match ui.tags.next_page() {
Err(e) => ui.info.set_info(&format!("{}", e)),
Ok(_) => (),
},
Ok(Key::Ctrl('p')) => match ui.tags.prev_page() {
Err(e) => ui.info.set_info(&format!("{}", e)),
Ok(_) => (),
},
Ok(Key::Char('\n')) => match ui.state { Ok(Key::Char('\n')) => match ui.state {
State::EditRepo => { State::EditRepo => {
ui.repo.confirm(); ui.repo.confirm();
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
State::SelectTag => { State::SelectTag => {
let mut repo = ui.repo.get(); let mut repo = ui.repo.get();
@ -172,7 +164,7 @@ impl Ui {
Ok(s) => s, Ok(s) => s,
}; };
ui.repo.set(repo.to_string()); ui.repo.set(repo.to_string());
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
} }
} }
@ -193,7 +185,7 @@ impl Ui {
Ok(s) => s, Ok(s) => s,
}; };
ui.repo.set(repo.to_string()); ui.repo.set(repo.to_string());
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
} }
} }

View File

@ -57,7 +57,7 @@ impl NoYaml {
// load tags if a repository was given thorugh paramter // load tags if a repository was given thorugh paramter
if load_repo { if load_repo {
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
//setup tui //setup tui
@ -100,22 +100,17 @@ impl NoYaml {
} }
Ok(Key::Ctrl('r')) => { Ok(Key::Ctrl('r')) => {
ui.repo.confirm(); ui.repo.confirm();
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
} }
Ok(Key::Ctrl('n')) => match ui.tags.next_page() {
Err(e) => ui.info.set_info(&format!("{}", e)),
Ok(_) => (),
},
Ok(Key::Ctrl('p')) => match ui.tags.prev_page() {
Err(e) => ui.info.set_info(&format!("{}", e)),
Ok(_) => (),
},
Ok(Key::Char('\n')) => match ui.state { Ok(Key::Char('\n')) => match ui.state {
State::EditRepo => { State::EditRepo => {
ui.repo.confirm(); ui.repo.confirm();
ui.tags = tag_list::TagList::with_repo(ui.repo.get()); ui.tags = tag_list::TagList::with_repo_name(ui.repo.get());
}
State::SelectTag => {
ui.tags.get_selected();
()
} }
_ => (),
}, },
Ok(Key::Char(key)) => match ui.state { Ok(Key::Char(key)) => match ui.state {
State::EditRepo => { State::EditRepo => {
@ -126,6 +121,21 @@ impl NoYaml {
ui.tags.handle_input(Key::Char(key)); ui.tags.handle_input(Key::Char(key));
} }
}, },
Ok(Key::Backspace) => match ui.state {
State::EditRepo => {
ui.info.set_info("Editing Repository");
ui.repo.handle_input(Key::Backspace);
}
State::SelectTag => (),
},
Ok(Key::Up) => match ui.state {
State::EditRepo => (),
State::SelectTag => ui.tags.handle_input(Key::Up),
},
Ok(Key::Down) => match ui.state {
State::EditRepo => (),
State::SelectTag => ui.tags.handle_input(Key::Down),
},
_ => (), _ => (),
} }

View File

@ -11,7 +11,7 @@ impl Info {
Self { Self {
info: String::from(info), info: String::from(info),
keys: String::from( keys: String::from(
"Tab Cycle widgets C-s Save C-r Reload C-q Quit C-n Next page C-p Previous page ↑ ↓ Select tags or image line", "Tab Cycle widgets C-s Save C-r Reload C-q Quit ↑ ↓ Select tags or image line",
), ),
} }
} }

View File

@ -6,105 +6,77 @@ use tui::widgets::{Block, Borders, List, ListState};
use crate::tags; use crate::tags;
#[derive(Debug)]
pub enum Error { pub enum Error {
NoneSelected, NoneSelected,
NoTags, NextPageSelected,
NoNextPage, SelectedStatus,
NoPrevPage,
} }
impl fmt::Display for Error { impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self { match self {
Error::NoTags => write!(f, "There are no tags"),
Error::NoneSelected => write!(f, "No tag selected"), Error::NoneSelected => write!(f, "No tag selected"),
Error::NoNextPage => write!(f, "No next page available"), Error::NextPageSelected => write!(f, "tried to get the next page"),
Error::NoPrevPage => write!(f, "No previous page available"), Error::SelectedStatus => write!(f, "Status message was selected"),
} }
} }
} }
/// used for creating a TagList enum Line {
pub enum Type {
Status(String), Status(String),
Repo(tags::Tags), Image(tags::Images),
}
impl fmt::Display for Line {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Line::Status(s) => write!(f, "{}", s),
Line::Image(i) => write!(f, "{}", i),
}
}
} }
pub struct TagList { pub struct TagList {
typ: Type, lines: Vec<Line>,
state: ListState, state: ListState,
tags: Option<tags::Tags>,
} }
impl TagList { impl TagList {
fn new(typ: Type) -> Self {
Self {
typ,
state: ListState::default(),
}
}
/// create a TagList with a status message
pub fn with_status(status: &str) -> Self { pub fn with_status(status: &str) -> Self {
Self::new(Type::Status(String::from(status))) Self {
} lines: vec![Line::Status(String::from(status))],
state: ListState::default(),
/// create a TagList tags: None,
pub fn with_repo(name: String) -> Self {
match tags::Tags::new(name) {
Err(e) => Self::with_status(&format!("{}", e)),
Ok(tags) => Self::new(Type::Repo(tags)),
} }
} }
/// display next page if possible pub fn with_repo_name(repo: String) -> Self {
pub fn next_page(&mut self) -> Result<(), Error> { match tags::Tags::new(repo) {
match &self.typ { Ok(tags) => Self::with_tags(tags),
Type::Status(_) => (), Err(_) => Self::with_status("input repo was not found"),
Type::Repo(tags) => match tags.next_page() {
Err(_) => return Err(Error::NoNextPage),
Ok(tags) => self.typ = Type::Repo(tags),
},
}
Ok(())
}
/// display previous page if possible
pub fn prev_page(&mut self) -> Result<(), Error> {
match &self.typ {
Type::Status(_) => (),
Type::Repo(tags) => match tags.prev_page() {
Err(_) => return Err(Error::NoPrevPage),
Ok(tags) => self.typ = Type::Repo(tags),
},
}
Ok(())
}
/// get a list of tag names with info
fn print_lines(&self) -> Vec<String> {
match &self.typ {
Type::Status(line) => vec![line.to_string()],
Type::Repo(tags) => tags.results.iter().map(|r| format!("{}", r)).collect(),
} }
} }
/// get the list of tag names pub fn with_tags(mut tags: tags::Tags) -> Self {
pub fn get_names(&self) -> Result<Vec<String>, Error> { let mut lines: Vec<Line> = tags
match &self.typ { .results
Type::Status(_) => Err(Error::NoTags), .iter()
Type::Repo(tags) => Ok(tags.results.iter().map(|r| r.tag_name.clone()).collect()), .map(|r| Line::Image(r.clone()))
} .collect();
}
/// get the selected tag or return an error match tags.next_page() {
pub fn get_selected(&self) -> Result<String, Error> { Err(_) => (),
match &self.typ { Ok(new_tags) => {
Type::Status(_) => Err(Error::NoTags), lines.push(Line::Status(String::from("load more tags")));
Type::Repo(_) => match self.state.selected() { tags = new_tags;
None => Err(Error::NoneSelected), }
Some(i) => Ok(self.get_names().unwrap()[i].clone()), };
},
Self {
lines,
state: ListState::default(),
tags: Some(tags),
} }
} }
@ -115,15 +87,11 @@ impl TagList {
Style::default().fg(Color::Gray) Style::default().fg(Color::Gray)
}; };
let lines = match &self.typ { let items: Vec<tui::widgets::ListItem> = self
Type::Status(line) => vec![line.clone()], .lines
Type::Repo(_) => self.print_lines(),
};
let items: Vec<tui::widgets::ListItem> = lines
.iter() .iter()
.map(|l| { .map(|l| {
tui::widgets::ListItem::new(l.clone()) tui::widgets::ListItem::new(format!("{}", l))
.style(Style::default().fg(Color::White).bg(Color::Black)) .style(Style::default().fg(Color::White).bg(Color::Black))
}) })
.collect(); .collect();
@ -151,24 +119,63 @@ impl TagList {
} }
} }
/// select next tag pub fn get_selected(&mut self) -> Result<String, Error> {
pub fn next(&mut self) {
match self.state.selected() { match self.state.selected() {
None if self.print_lines().len() > 0 => self.state.select(Some(0)), None => Err(Error::NoneSelected),
Some(i) if i == self.lines.len() - 1 => {
self.load_next_page();
Err(Error::NextPageSelected)
}
Some(i) => match &self.lines[i] {
Line::Status(_) => Err(Error::SelectedStatus),
Line::Image(i) => Ok(i.tag_name.clone()),
},
}
}
fn load_next_page(&mut self) {
match &self.tags {
Some(tags) => match tags.next_page() {
Err(_) => (),
Ok(new_tags) => {
//load new tags object
self.tags = Some(new_tags);
//remove "load next page"
let next_page = self.lines.pop();
//add tags
for image in &self.tags.as_ref().unwrap().results {
self.lines.push(Line::Image(image.clone()));
}
//readd next page
match self.tags.as_ref().unwrap().next_page {
None => (), None => (),
Some(i) if i == self.print_lines().len() - 1 => self.state.select(Some(0)), Some(_) => self.lines.push(next_page.unwrap()),
}
}
},
None => (),
}
}
/// select next tag
fn next(&mut self) {
match self.state.selected() {
None if self.lines.len() > 0 => self.state.select(Some(0)),
None => (),
Some(i) if i == self.lines.len() - 1 => self.state.select(Some(0)),
Some(i) => self.state.select(Some(i + 1)), Some(i) => self.state.select(Some(i + 1)),
} }
} }
/// select previous tag /// select previous tag
pub fn previous(&mut self) { fn previous(&mut self) {
match self.state.selected() { match self.state.selected() {
None if self.print_lines().len() > 0 => { None if self.lines.len() > 0 => self.state.select(Some(self.lines.len())),
self.state.select(Some(self.print_lines().len()))
}
None => (), None => (),
Some(i) if i == 0 => self.state.select(Some(self.print_lines().len() - 1)), Some(i) if i == 0 => self.state.select(Some(self.lines.len() - 1)),
Some(i) => self.state.select(Some(i - 1)), Some(i) => self.state.select(Some(i - 1)),
} }
} }