Skip to content

Commit

Permalink
feat: initial implementation of parent selector
Browse files Browse the repository at this point in the history
  • Loading branch information
wllfaria committed Jun 13, 2024
1 parent 34938e9 commit 2bf01fd
Show file tree
Hide file tree
Showing 8 changed files with 401 additions and 56 deletions.
10 changes: 7 additions & 3 deletions hac-client/src/pages/collection_viewer/collection_viewer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ pub struct ExplorerLayout {
pub enum CollectionViewerOverlay {
None,
CreateRequest,
SelectParentDir,
EditRequest,
CreateDirectory,
HeadersHelp,
Expand Down Expand Up @@ -264,17 +265,20 @@ impl Renderable for CollectionViewer<'_> {
CollectionViewerOverlay::CreateDirectory => {
self.sidebar.draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::SelectParentDir => {
self.sidebar.draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::EditRequest => {
self.sidebar.draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::HeadersHelp => {
self.request_editor.draw_overlay(frame, overlay)?
self.request_editor.draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::HeadersDelete => {
self.request_editor.draw_overlay(frame, overlay)?
self.request_editor.draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::HeadersForm(_) => {
self.request_editor.draw_overlay(frame, overlay)?
self.request_editor.draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::None => {}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::pages::collection_viewer::collection_viewer::CollectionViewerOverlay;
use crate::pages::overlay::make_overlay;
use crate::pages::{collection_viewer::collection_store::CollectionStore, Eventful, Renderable};

use std::ops::{Div, Sub};
use std::ops::{Div, Mul, Sub};
use std::{cell::RefCell, ops::Add, rc::Rc};

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
Expand Down Expand Up @@ -68,7 +68,7 @@ impl<'he> HeadersEditor<'he> {
scroll: 0,
selected_row: 5,
row_height,
amount_on_view: layout.content_size.height.div(row_height).into(),
amount_on_view: layout.content_size.height.div_ceil(row_height).into(),
layout,
logo_idx,
}
Expand Down Expand Up @@ -237,39 +237,41 @@ impl Renderable for HeadersEditor<'_> {
.fg(self.colors.normal.yellow)
.bold();

Layout::default()
.constraints((0..self.amount_on_view).map(|_| Constraint::Length(self.row_height)))
.direction(Direction::Vertical)
.split(self.layout.content_size)
for (idx, header) in headers
.iter()
.map(|row| {
Layout::default()
.constraints([
Constraint::Length(2),
Constraint::Fill(1),
Constraint::Length(1),
Constraint::Fill(1),
Constraint::Length(1),
Constraint::Length(7),
])
.direction(Direction::Horizontal)
.split(*row)
.iter()
.enumerate()
// we are removing the empty space we just created between vallue and
// the enabled checkbox the idea is to have something like this:
//
// Name Value Enabled
// > Header-Name Header-Value [x]
// Header-Name Header-Value [x]
//
.filter(|(idx, _)| idx.ne(&2) && idx.ne(&4))
.map(|(_, rect)| *rect)
.collect::<Vec<_>>()
})
.zip(headers.iter().skip(self.scroll).take(self.amount_on_view))
.skip(self.scroll)
.take(self.amount_on_view)
.enumerate()
.for_each(|(idx, pair)| self.draw_row(pair, frame, idx));
{
let size = self.layout.content_size;
let offset = self.row_height.mul(idx as u16);
let size = Rect::new(size.x, size.y.add(offset), size.width, self.row_height);
let layout = Layout::default()
.constraints([
Constraint::Length(2),
Constraint::Fill(1),
Constraint::Length(1),
Constraint::Fill(1),
Constraint::Length(1),
Constraint::Length(7),
])
.direction(Direction::Horizontal)
.split(size)
.iter()
.enumerate()
// the enabled checkbox the idea is to have something like this:
//
// Name Value Enabled
// > Header-Name Header-Value [x]
// Header-Name Header-Value [x]
//
.filter(|(idx, _)| idx.ne(&2) && idx.ne(&4))
.map(|(_, rect)| *rect)
.collect::<Vec<_>>();

let pair = (layout, header);
self.draw_row(pair, frame, idx);
}

let mut scrollbar_state = ScrollbarState::new(headers.len())
.content_length(self.row_height.into())
Expand All @@ -292,6 +294,12 @@ impl Renderable for HeadersEditor<'_> {

fn resize(&mut self, new_size: Rect) {
self.layout = build_layout(new_size, self.row_height);
self.amount_on_view = self
.layout
.content_size
.height
.div_ceil(self.row_height)
.into();
}
}

Expand Down Expand Up @@ -369,10 +377,10 @@ impl Eventful for HeadersEditor<'_> {
let total_headers = headers.len();

match key_event.code {
KeyCode::Char('j') => {
KeyCode::Char('j') | KeyCode::Down => {
self.selected_row = usize::min(self.selected_row.add(1), total_headers.sub(1))
}
KeyCode::Char('k') => {
KeyCode::Char('k') | KeyCode::Up => {
self.selected_row = self.selected_row.saturating_sub(1);
}
KeyCode::Char('?') => {
Expand Down
20 changes: 19 additions & 1 deletion hac-client/src/pages/collection_viewer/sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ mod create_directory_form;
mod create_request_form;
mod edit_request_form;
mod request_form;
mod select_request_parent;

use hac_core::collection::types::{Request, RequestKind, RequestMethod};

Expand Down Expand Up @@ -58,7 +59,13 @@ enum FormVariant<'sbar> {
/// this is just a helper trait to be able to return the inner reference of the form
/// from the enum as we cannot return it like:
/// `&mut dyn Renderable + Eventful<Result = RequestFormEvent>;`
pub trait RequestFormTrait: Renderable + Eventful<Result = RequestFormEvent> {}
pub trait RequestFormTrait: Renderable + Eventful<Result = RequestFormEvent> {
fn draw_overlay(
&mut self,
frame: &mut Frame,
overlay: CollectionViewerOverlay,
) -> anyhow::Result<()>;
}

impl FormVariant<'_> {
pub fn inner(&mut self) -> &mut dyn RequestFormTrait {
Expand Down Expand Up @@ -123,6 +130,9 @@ impl<'sbar> Sidebar<'sbar> {
CollectionViewerOverlay::EditRequest => {
self.request_form.inner().draw(frame, frame.size())?;
}
CollectionViewerOverlay::SelectParentDir => {
self.request_form.inner().draw_overlay(frame, overlay)?;
}
CollectionViewerOverlay::CreateDirectory => {
self.directory_form.draw(frame, frame.size())?;
}
Expand Down Expand Up @@ -211,6 +221,14 @@ impl<'a> Eventful for Sidebar<'a> {
None => return Ok(None),
}
}
CollectionViewerOverlay::SelectParentDir => {
let result = self.request_form.inner().handle_key_event(key_event)?;
assert!(
result.is_none(),
"should never return an event when selecting parent dir"
);
return Ok(None);
}
CollectionViewerOverlay::CreateDirectory => {
match self.directory_form.handle_key_event(key_event)? {
Some(CreateDirectoryFormEvent::Confirm) => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
use hac_core::collection::types::*;

use super::request_form::FormField;
use super::request_form::RequestForm;
use super::request_form::RequestFormCreate;
use super::request_form::RequestFormEvent;
use super::select_request_parent::{SelectRequestParent, SelectRequestParentEvent};
use super::RequestFormTrait;
use crate::ascii::LOGO_ASCII;
use crate::pages::collection_viewer::collection_store::CollectionStore;
use crate::pages::collection_viewer::sidebar::request_form::FormField;
use crate::pages::collection_viewer::sidebar::request_form::RequestForm;
use crate::pages::collection_viewer::sidebar::request_form::RequestFormCreate;
use crate::pages::collection_viewer::sidebar::request_form::RequestFormEvent;
use crate::pages::collection_viewer::sidebar::RequestFormTrait;
use crate::pages::Eventful;
use crate::pages::collection_viewer::collection_viewer::CollectionViewerOverlay;
use crate::pages::{Eventful, Renderable};

use std::cell::RefCell;
use std::ops::Sub;
Expand All @@ -16,8 +18,21 @@ use std::sync::{Arc, RwLock};

use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
use rand::Rng;
use ratatui::Frame;

impl<'rf> RequestFormTrait for RequestForm<'rf, RequestFormCreate> {
fn draw_overlay(
&mut self,
frame: &mut Frame,
overlay: CollectionViewerOverlay,
) -> anyhow::Result<()> {
if let CollectionViewerOverlay::SelectParentDir = overlay {
self.parent_selector.draw(frame, frame.size())?;
}

impl<'rf> RequestFormTrait for RequestForm<'rf, RequestFormCreate> {}
Ok(())
}
}

impl<'rf> RequestForm<'rf, RequestFormCreate> {
pub fn new(
Expand All @@ -28,6 +43,7 @@ impl<'rf> RequestForm<'rf, RequestFormCreate> {

RequestForm {
colors,
parent_selector: SelectRequestParent::new(colors, collection_store.clone()),
collection_store,
logo_idx,
request_name: String::default(),
Expand All @@ -36,6 +52,7 @@ impl<'rf> RequestForm<'rf, RequestFormCreate> {
focused_field: FormField::Name,
marker: std::marker::PhantomData,
request: None,
no_available_parent_timer: None,
}
}
}
Expand Down Expand Up @@ -67,6 +84,10 @@ impl Eventful for RequestForm<'_, RequestFormCreate> {
.get_or_insert(Arc::new(RwLock::new(vec![])));
let mut requests = requests.write().unwrap();

if self.request_name.is_empty() {
self.request_name = String::from("unnamed request");
}

requests.push(RequestKind::Single(Arc::new(RwLock::new(Request {
id: uuid::Uuid::new_v4().to_string(),
body: None,
Expand Down Expand Up @@ -117,7 +138,41 @@ impl Eventful for RequestForm<'_, RequestFormCreate> {
KeyCode::Char('l') => self.request_method = self.request_method.next(),
_ => {}
},
FormField::Parent => {}
FormField::Parent => {
if let KeyCode::Char(' ') = key_event.code {
let mut store = self.collection_store.borrow_mut();
let collection = store
.get_collection()
.expect("tried to select a parent without a collection");
let collection = collection.borrow();

let Some(requests) = collection.requests.as_ref() else {
drop(store);
self.set_no_parent_timer();
return Ok(None);
};

let requests = requests.read().unwrap();
if requests.is_empty() {
drop(store);
self.set_no_parent_timer();
return Ok(None);
}

if requests
.iter()
.filter(|req| req.is_dir())
.collect::<Vec<_>>()
.is_empty()
{
drop(store);
self.set_no_parent_timer();
return Ok(None);
}

store.push_overlay(CollectionViewerOverlay::SelectParentDir);
}
}
}

Ok(None)
Expand Down
Loading

0 comments on commit 2bf01fd

Please sign in to comment.