Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/action.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::mode::Mode;
use std::{fmt, string::ToString};

use serde::{
Expand All @@ -16,7 +17,12 @@ pub enum Action {
Quit,
Refresh,
Error(String),
NextTable,
Mode(Mode),
NextMode(Mode),
PreviousMode(Mode),
Help,
Pool,
DagRun,
Code,
Clear,
Expand Down
558 changes: 155 additions & 403 deletions src/app.rs

Large diffs are not rendered by default.

245 changes: 239 additions & 6 deletions src/components.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,26 @@
use crate::components::table::table::LinkedTable;
use crate::components::table::table::{Table, Tables};
use crate::mode::ObservableMode;
use std::cell::{Ref, RefCell, RefMut};
use std::fmt::Debug;
use std::rc::Rc;

use color_eyre::eyre::Result;
use crossterm::event::{KeyEvent, MouseEvent};
use ratatui::layout::Rect;
use tokio::sync::mpsc::UnboundedSender;

use crate::context_data::ContextData;
use crate::main_layout::{Chunk, MainLayout};
use crate::mode::Mode;
use crate::{
action::Action,
config::Config,
tui::{Event, Frame},
};
use std::sync::Arc;
use tokio::sync::Mutex;
use tokio::sync::MutexGuard;

pub mod ascii;
pub mod command;
Expand All @@ -17,7 +29,7 @@ pub mod context_informations;
pub mod fps;
pub mod shortcut;
pub mod status_bar;
pub mod table_dag_runs;
pub mod table;

/// `Component` is a trait that represents a visual and interactive element of the user interface.
/// Implementors of this trait can be registered with the main application loop and will be able to receive events,
Expand Down Expand Up @@ -70,7 +82,13 @@ pub trait Component {
/// # Returns
///
/// * `Result<Option<Action>>` - An action to be processed or none.
fn handle_events(&mut self, event: Option<Event>) -> Result<Option<Action>> {
fn handle_events(
&mut self,
event: Option<&Event>,
context_data: &mut MutexGuard<'_, ContextData>,
mode: &ObservableMode,
tables: &mut Tables,
) -> Result<Option<Action>> {
let r = match event {
Some(Event::Key(key_event)) => self.handle_key_events(key_event)?,
Some(Event::Mouse(mouse_event)) => self.handle_mouse_events(mouse_event)?,
Expand Down Expand Up @@ -101,7 +119,7 @@ pub trait Component {
///
/// * `Result<Option<Action>>` - An action to be processed or none.
#[allow(unused_variables)]
fn handle_key_events(&mut self, key: KeyEvent) -> Result<Option<Action>> {
fn handle_key_events(&mut self, key: &KeyEvent) -> Result<Option<Action>> {
Ok(None)
}
/// Handle mouse events and produce actions if necessary.
Expand All @@ -114,7 +132,7 @@ pub trait Component {
///
/// * `Result<Option<Action>>` - An action to be processed or none.
#[allow(unused_variables)]
fn handle_mouse_events(&mut self, mouse: MouseEvent) -> Result<Option<Action>> {
fn handle_mouse_events(&mut self, mouse: &MouseEvent) -> Result<Option<Action>> {
Ok(None)
}
/// Update the state of the component based on a received action. (REQUIRED)
Expand All @@ -127,7 +145,12 @@ pub trait Component {
///
/// * `Result<Option<Action>>` - An action to be processed or none.
#[allow(unused_variables)]
fn update(&mut self, action: Action) -> Result<Option<Action>> {
fn update(
&mut self,
action: Action,
context_data: &MutexGuard<'_, ContextData>,
tables: &MutexGuard<'_, LinkedTable>,
) -> Result<Option<Action>> {
Ok(None)
}
/// Render the component on the screen. (REQUIRED)
Expand All @@ -140,5 +163,215 @@ pub trait Component {
/// # Returns
///
/// * `Result<()>` - An Ok result or an error.
fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()>;
fn draw(
&mut self,
f: &mut Frame<'_>,
area: Rect,
context_data: &MutexGuard<'_, ContextData>,
table: &MutexGuard<'_, dyn Table>,
mode: Mode,
) -> Result<()>;
}

impl Debug for dyn Component {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", self)
}
}

pub type NodeComponentRef = Option<Rc<RefCell<NodeComponent>>>;

#[derive(Debug)]
pub struct NodeComponent {
pub value: Rc<RefCell<dyn Component>>,
pub next: NodeComponentRef,
pub chunk: Chunk,
pub display_mode: Option<Mode>,
}

impl NodeComponent {
pub fn new(
component: Rc<RefCell<dyn Component>>,
chunk: Chunk,
display_mode: Option<Mode>,
) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(NodeComponent {
value: component,
next: None,
chunk,
display_mode,
}))
}
}

#[derive(Debug)]
pub struct LinkedComponent {
pub head: NodeComponentRef,
}

impl LinkedComponent {
pub fn new() -> Self {
LinkedComponent { head: None }
}

pub fn append(
&mut self,
component: Rc<RefCell<dyn Component>>,
chunk: Chunk,
display_mode: Option<Mode>,
) {
let new_node: Rc<RefCell<NodeComponent>> =
NodeComponent::new(component, chunk, display_mode);
match self.head {
None => {
self.head = Some(new_node);
}
Some(ref head) => {
let mut current = head.clone();
loop {
let next = { current.borrow().next.clone() };
match next {
Some(n) => current = n,
None => {
current.borrow_mut().next = Some(new_node.clone());
break;
}
}
}
}
}
}

pub fn draw_components<F>(
&mut self,
f: &mut Frame<'_>,
get_chunk: F,
mode: Mode,
context_data: &MutexGuard<'_, ContextData>,
table: &MutexGuard<'_, dyn Table>,
) -> Result<()>
where
F: Fn(&Chunk) -> Rect,
{
let mut current: Option<Rc<RefCell<NodeComponent>>> = self.head.clone();
while let Some(node) = current {
let node: Ref<NodeComponent> = node.borrow();
let chunk: &Chunk = &node.chunk;
let display_mode: Option<Mode> = node.display_mode;
let area: Rect = get_chunk(chunk);
if let Some(observable_mode) = display_mode {
if observable_mode != mode {
current = node.next.clone();
continue;
}
}
node.value
.borrow_mut()
.draw(f, area, context_data, table, mode)?;
current = node.next.clone();
}
Ok(())
}

pub fn register_action_components(&self, tx: &UnboundedSender<Action>) {
let mut current: Option<Rc<RefCell<NodeComponent>>> = self.head.clone();
while let Some(node) = current {
let node: Ref<NodeComponent> = node.borrow();
let mut component = node.value.borrow_mut();
component
.register_action_handler(tx.clone())
.expect("TODO: panic message");
current = node.next.clone();
}
}

pub fn register_config_components(&self, config: &Config) {
let mut current: Option<Rc<RefCell<NodeComponent>>> = self.head.clone();
while let Some(node) = current {
let node: Ref<NodeComponent> = node.borrow();
let mut component = node.value.borrow_mut();
component
.register_config_handler(config.clone())
.expect("TODO: panic message");
current = node.next.clone();
}
}

pub fn handle_events(
&self,
option: Option<&Event>,
context_data: &mut MutexGuard<'_, ContextData>,
mode: &ObservableMode,
tables: &mut Tables,
) -> Result<Option<Action>> {
let mut current: Option<Rc<RefCell<NodeComponent>>> = self.head.clone();
while let Some(node) = current {
let node: Ref<NodeComponent> = node.borrow();
let mut component = node.value.borrow_mut();
let action = component.handle_events(option, context_data, mode, tables)?;
current = node.next.clone();
if current.is_none() && action.is_some() {
return Ok(action);
}
}
Ok(None)
}

pub fn handle_actions(
&self,
action: Action,
context_data: &MutexGuard<'_, ContextData>,
tables: &MutexGuard<'_, LinkedTable>,
) -> Result<Option<Action>> {
let mut current: Option<Rc<RefCell<NodeComponent>>> = self.head.clone();
while let Some(node) = current {
let node: Ref<NodeComponent> = node.borrow();
let mut component = node.value.borrow_mut();
component.update(action.clone(), context_data, tables);
current = node.next.clone();
if current.is_none() {
return Ok(Some(action));
}
}
Ok(None)
}

pub fn get_component_by_idx(&self, usr_idx: usize) -> Option<Rc<RefCell<dyn Component>>> {
let mut current: Option<Rc<RefCell<NodeComponent>>> = self.head.clone();
let mut idx: usize = 0;
while let Some(node) = current {
let node: Ref<NodeComponent> = node.borrow();
if idx == usr_idx {
return Some(node.value.clone());
}
current = node.next.clone();
}
None
}

pub fn iter(&self) -> IterComponent {
IterComponent {
current: self.head.clone(),
}
}
}

pub struct IterComponent {
pub(crate) current: NodeComponentRef,
}

impl Iterator for IterComponent {
type Item = Rc<RefCell<NodeComponent>>;

fn next(&mut self) -> Option<Self::Item> {
let current: Option<Rc<RefCell<NodeComponent>>> = self.current.take();
if current.is_none() {
return None;
} else {
let current: Rc<RefCell<NodeComponent>> = current.unwrap();
let current: RefMut<NodeComponent> = current.borrow_mut();
self.current = current.next.clone();
current.next.clone()
}
}
}
21 changes: 19 additions & 2 deletions src/components/ascii.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
use crate::components::table::table::LinkedTable;
use crate::components::Table;
use crate::mode::Mode;
use std::{collections::HashMap, time::Duration};
use tokio::sync::MutexGuard;

use crate::context_data::ContextData;
use color_eyre::eyre::Result;
use color_eyre::owo_colors::OwoColorize;
use crossterm::event::{KeyCode, KeyEvent};
Expand Down Expand Up @@ -47,12 +52,24 @@ impl Component for Ascii {
Ok(())
}

fn update(&mut self, action: Action) -> Result<Option<Action>> {
fn update(
&mut self,
action: Action,
context_data: &MutexGuard<'_, ContextData>,
tables: &MutexGuard<'_, LinkedTable>,
) -> Result<Option<Action>> {
{}
Ok(None)
}

fn draw(&mut self, f: &mut Frame<'_>, area: Rect) -> Result<()> {
fn draw(
&mut self,
f: &mut Frame<'_>,
area: Rect,
context_data: &MutexGuard<'_, ContextData>,
table: &MutexGuard<'_, dyn Table>,
mode: Mode,
) -> Result<()> {
let block = Paragraph::new(self.ascii)
.block(Block::new())
.style(Style::default().fg(Color::Magenta));
Expand Down
Loading