Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
refactor: Adapt issue creation to generic form
Erik Kundt committed 2 years ago
commit 96967897b0a436d3298d0d21562081fe3bb3052b
parent de2362134ac06bdf7c021795a207b079c4cfce08
3 files changed +99 -13
modified src/app/page.rs
@@ -7,7 +7,7 @@ use radicle::cob::patch::{Patch, PatchId};

use radicle_tui::cob;
use radicle_tui::ui::widget::common::context::{Progress, Shortcuts};
-
use tuirealm::{AttrValue, Attribute, Frame, NoUserEvent, StateValue, Sub, SubClause};
+
use tuirealm::{AttrValue, Attribute, Frame, NoUserEvent, State, StateValue, Sub, SubClause};

use radicle_tui::ui::context::Context;
use radicle_tui::ui::layout;
@@ -15,7 +15,8 @@ use radicle_tui::ui::theme::Theme;
use radicle_tui::ui::widget::{self, Widget};

use super::{
-
    subscription, Application, Cid, HomeCid, HomeMessage, IssueCid, IssueMessage, Message, PatchCid,
+
    subscription, Application, Cid, HomeCid, HomeMessage, IssueCid, IssueCobMessage, IssueMessage,
+
    Message, PatchCid, PopupMessage,
};

/// `tuirealm`'s event and prop system is designed to work with flat component hierarchies.
@@ -139,8 +140,6 @@ impl HomeView {
        theme: &Theme,
        cid: HomeCid,
    ) -> Result<()> {
-
        use tuirealm::State;
-

        let context = match cid {
            HomeCid::IssueBrowser => {
                let state = app.state(&Cid::Home(HomeCid::IssueBrowser))?;
@@ -197,9 +196,6 @@ impl ViewPage for HomeView {
        context: &Context,
        theme: &Theme,
    ) -> Result<()> {
-
        // let issue = context.issues().first().cloned();
-
        // let patch = context.patches().first().cloned();
-

        let navigation = widget::home::navigation(theme);
        let header = widget::common::app_header(context, theme, Some(navigation)).to_boxed();

@@ -386,8 +382,6 @@ impl IssuePage {
        theme: &Theme,
        cid: IssueCid,
    ) -> Result<()> {
-
        use tuirealm::State;
-

        let context = match cid {
            IssueCid::List => {
                let state = app.state(&Cid::Issue(IssueCid::List))?;
@@ -564,6 +558,68 @@ impl ViewPage for IssuePage {
                }
                return Ok(Some(Message::Issue(IssueMessage::Focus(IssueCid::List))));
            }
+
            Message::FormSubmitted(id) => {
+
                if id == widget::issue::FORM_ID_EDIT {
+
                    let state = app.state(&Cid::Issue(IssueCid::Form))?;
+
                    if let State::Linked(mut states) = state {
+
                        let mut missing_values = vec![];
+

+
                        let title = match states.front() {
+
                            Some(State::One(StateValue::String(title))) if !title.is_empty() => {
+
                                Some(title.clone())
+
                            }
+
                            _ => None,
+
                        };
+
                        states.pop_front();
+

+
                        let tags = match states.front() {
+
                            Some(State::One(StateValue::String(tags))) => Some(tags.clone()),
+
                            _ => Some(String::from("[]")),
+
                        };
+
                        states.pop_front();
+

+
                        let assignees = match states.front() {
+
                            Some(State::One(StateValue::String(assignees))) => {
+
                                Some(assignees.clone())
+
                            }
+
                            _ => Some(String::from("[]")),
+
                        };
+
                        states.pop_front();
+

+
                        let description = match states.front() {
+
                            Some(State::One(StateValue::String(description)))
+
                                if !description.is_empty() =>
+
                            {
+
                                Some(description.clone())
+
                            }
+
                            _ => None,
+
                        };
+
                        states.pop_front();
+

+
                        if title.is_none() {
+
                            missing_values.push("title");
+
                        }
+
                        if description.is_none() {
+
                            missing_values.push("description");
+
                        }
+

+
                        // show error popup if missing.
+
                        if !missing_values.is_empty() {
+
                            let error = format!("Missing fields: {:?}", missing_values);
+
                            return Ok(Some(Message::Popup(PopupMessage::Error(error))));
+
                        } else {
+
                            return Ok(Some(Message::Issue(IssueMessage::Cob(
+
                                IssueCobMessage::Create {
+
                                    title: title.unwrap(),
+
                                    tags: tags.unwrap(),
+
                                    assignees: assignees.unwrap(),
+
                                    description: description.unwrap(),
+
                                },
+
                            ))));
+
                        }
+
                    }
+
                }
+
            }
            _ => {}
        }

modified src/ui/widget.rs
@@ -7,7 +7,7 @@ mod utils;
use std::ops::Deref;

use tuirealm::command::{Cmd, CmdResult};
-
use tuirealm::props::{AttrValue, Attribute, Color, Props};
+
use tuirealm::props::{AttrValue, Attribute, Color, Layout, Props};
use tuirealm::tui::layout::Rect;
use tuirealm::{Frame, MockComponent, State};

@@ -78,6 +78,11 @@ impl<T: WidgetComponent> Widget<T> {
        self
    }

+
    pub fn layout(mut self, layout: Layout) -> Self {
+
        self.attr(Attribute::Layout, AttrValue::Layout(layout));
+
        self
+
    }
+

    pub fn to_boxed(self) -> Box<Self> {
        Box::new(self)
    }
modified src/ui/widget/issue.rs
@@ -22,6 +22,8 @@ use crate::ui::widget::common::form::TextField;

use super::*;

+
pub const FORM_ID_EDIT: &str = "edit-form";
+

pub struct LargeList {
    items: Vec<IssueItem>,
    list: Widget<LabeledContainer>,
@@ -329,9 +331,32 @@ pub fn description(
    Widget::new(body)
}

-
pub fn new_form(_context: &Context, theme: &Theme) -> Widget<NewForm> {
-
    let form = NewForm::new(theme);
-
    Widget::new(form)
+
pub fn new_form(_context: &Context, theme: &Theme) -> Widget<Form> {
+
    use tuirealm::props::Layout;
+

+
    let title = Widget::new(TextField::new(theme.clone(), "Title")).to_boxed();
+
    let tags = Widget::new(TextField::new(theme.clone(), "Labels (bug, ...)")).to_boxed();
+
    let assignees = Widget::new(TextField::new(
+
        theme.clone(),
+
        "Assignees (z6MkvAdxCp1oLVVTsqYvev9YrhSN3gBQNUSM45hhy4pgkexk, ...)",
+
    ))
+
    .to_boxed();
+
    let description = Widget::new(TextArea::new(theme.clone(), "Description")).to_boxed();
+
    let inputs: Vec<Box<dyn MockComponent>> = vec![title, tags, assignees, description];
+

+
    let layout = Layout::default().constraints(
+
        [
+
            Constraint::Length(3),
+
            Constraint::Length(3),
+
            Constraint::Length(3),
+
            Constraint::Min(3),
+
        ]
+
        .as_ref(),
+
    );
+

+
    Widget::new(Form::new(theme.clone(), inputs))
+
        .custom(Form::PROP_ID, AttrValue::String(String::from(FORM_ID_EDIT)))
+
        .layout(layout)
}

pub fn details(