Radish alpha
r
Radicle terminal user interface
Radicle
Git (anonymous pull)
Log in to clone via SSH
bin: Rename action to message
Erik Kundt committed 2 years ago
commit a16c82f2d782dcb2721351eacc407d0fba635f2b
parent 746e8eff5c90b93005a804b0ece1c9ef7f106702
6 files changed +225 -225
modified bin/commands/inbox/select.rs
@@ -195,7 +195,7 @@ impl TryFrom<&Context> for State {
    }
}

-
pub enum Action {
+
pub enum Message {
    Exit { selection: Option<Selection> },
    Select { selected: Option<usize> },
    BrowserPageSize(usize),
@@ -210,42 +210,42 @@ pub enum Action {
}

impl store::State<Selection> for State {
-
    type Action = Action;
+
    type Message = Message;

    fn tick(&self) {}

-
    fn handle_action(&mut self, action: Action) -> Option<Exit<Selection>> {
-
        match action {
-
            Action::Exit { selection } => Some(Exit { value: selection }),
-
            Action::Select { selected } => {
+
    fn update(&mut self, message: Message) -> Option<Exit<Selection>> {
+
        match message {
+
            Message::Exit { selection } => Some(Exit { value: selection }),
+
            Message::Select { selected } => {
                self.browser.selected = selected;
                None
            }
-
            Action::BrowserPageSize(size) => {
+
            Message::BrowserPageSize(size) => {
                self.browser.page_size = size;
                None
            }
-
            Action::HelpPageSize(size) => {
+
            Message::HelpPageSize(size) => {
                self.help.page_size = size;
                None
            }
-
            Action::OpenSearch => {
+
            Message::OpenSearch => {
                self.browser.show_search = true;
                None
            }
-
            Action::UpdateSearch { value } => {
+
            Message::UpdateSearch { value } => {
                self.browser.search.write(value);
                self.browser.filter = NotificationItemFilter::from_str(&self.browser.search.read())
                    .unwrap_or_default();

                None
            }
-
            Action::ApplySearch => {
+
            Message::ApplySearch => {
                self.browser.search.apply();
                self.browser.show_search = false;
                None
            }
-
            Action::CloseSearch => {
+
            Message::CloseSearch => {
                self.browser.search.reset();
                self.browser.show_search = false;
                self.browser.filter = NotificationItemFilter::from_str(&self.browser.search.read())
@@ -253,15 +253,15 @@ impl store::State<Selection> for State {

                None
            }
-
            Action::OpenHelp => {
+
            Message::OpenHelp => {
                self.pages.push(Page::Help);
                None
            }
-
            Action::LeavePage => {
+
            Message::LeavePage => {
                self.pages.pop();
                None
            }
-
            Action::ScrollHelp { progress } => {
+
            Message::ScrollHelp { progress } => {
                self.help.progress = progress;
                None
            }
@@ -277,7 +277,7 @@ impl App {
    pub async fn run(&self) -> Result<Option<Selection>> {
        let channel = Channel::default();
        let state = State::try_from(&self.context)?;
-
        let window: Window<State, Action, Page> = Window::new(&state, channel.tx.clone())
+
        let window: Window<State, Message, Page> = Window::new(&state, channel.tx.clone())
            .page(
                Page::Browse,
                BrowserPage::new(&state, channel.tx.clone()).to_boxed(),
modified bin/commands/inbox/select/ui.rs
@@ -28,9 +28,9 @@ use tui::Selection;

use crate::tui_inbox::common::{InboxOperation, Mode, RepositoryMode, SelectionMode};

-
use super::{Action, State};
+
use super::{Message, State};

-
type BoxedWidget = widget::BoxedWidget<State, Action>;
+
type BoxedWidget = widget::BoxedWidget<State, Message>;

#[derive(Clone)]
pub struct BrowserProps<'a> {
@@ -113,7 +113,7 @@ impl<'a> BoxedAny for BrowserProps<'a> {}

pub struct Browser<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: BrowserProps<'a>,
    /// Notification widget
@@ -123,18 +123,18 @@ pub struct Browser<'a> {
}

impl<'a: 'static> Widget for Browser<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self {
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self {
        let props = BrowserProps::from(state);

        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: props.clone(),
-
            notifications: Container::new(state, action_tx.clone())
+
            notifications: Container::new(state, tx.clone())
                .header(
-
                    Header::new(state, action_tx.clone())
+
                    Header::new(state, tx.clone())
                        .columns(
                            [
                                Column::new("", Constraint::Length(0)),
@@ -145,14 +145,14 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .cutoff(props.cutoff, props.cutoff_after)
                        .to_boxed(),
                )
-
                .content(Box::<Table<State, Action, NotificationItem, 9>>::new(
-
                    Table::new(state, action_tx.clone())
+
                .content(Box::<Table<State, Message, NotificationItem, 9>>::new(
+
                    Table::new(state, tx.clone())
                        .on_event(|table| {
                            table
-
                                .downcast_mut::<Table<State, Action, NotificationItem, 9>>()
+
                                .downcast_mut::<Table<State, Message, NotificationItem, 9>>()
                                .and_then(|table| {
                                    table
-
                                        .send(Action::Select {
+
                                        .send(Message::Select {
                                            selected: table.selected(),
                                        })
                                        .ok()
@@ -171,7 +171,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        }),
                ))
                .footer(
-
                    Footer::new(state, action_tx.clone())
+
                    Footer::new(state, tx.clone())
                        .on_update(|state| {
                            FooterProps::default()
                                .columns(browse_footer(&BrowserProps::from(state)))
@@ -185,7 +185,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .to_boxed()
                })
                .to_boxed(),
-
            search: Search::new(state, action_tx.clone()).to_boxed(),
+
            search: Search::new(state, tx.clone()).to_boxed(),
        }
    }

@@ -195,7 +195,7 @@ impl<'a: 'static> Widget for Browser<'a> {
        } else {
            match key {
                Key::Char('/') => {
-
                    let _ = self.send(Action::OpenSearch);
+
                    let _ = self.send(Message::OpenSearch);
                }
                Key::Char('\n') => {
                    self.props
@@ -210,7 +210,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                            };

                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(selection),
                                })
                                .ok()
@@ -222,7 +222,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .and_then(|selected| self.props.notifications.get(selected))
                        .and_then(|notif| {
                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(
                                        Selection::default()
                                            .with_operation(InboxOperation::Clear.to_string())
@@ -259,11 +259,11 @@ impl<'a: 'static> Widget for Browser<'a> {
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -305,7 +305,7 @@ impl<'a> BoxedAny for BrowserPageProps<'a> {}

pub struct BrowserPage<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: BrowserPageProps<'a>,
    /// Sections widget
@@ -315,17 +315,17 @@ pub struct BrowserPage<'a> {
}

impl<'a: 'static> Widget for BrowserPage<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self {
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self {
        let props = BrowserPageProps::from(state);

        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: props.clone(),
-
            sections: SectionGroup::new(state, action_tx.clone())
-
                .section(Browser::new(state, action_tx.clone()).to_boxed())
+
            sections: SectionGroup::new(state, tx.clone())
+
                .section(Browser::new(state, tx.clone()).to_boxed())
                .on_update(|state| {
                    let props = BrowserPageProps::from(state);
                    SectionGroupProps::default()
@@ -333,7 +333,7 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
                        .to_boxed()
                })
                .to_boxed(),
-
            shortcuts: Shortcuts::new(state, action_tx.clone())
+
            shortcuts: Shortcuts::new(state, tx.clone())
                .on_update(|state| {
                    ShortcutsProps::default()
                        .shortcuts(&BrowserPageProps::from(state).shortcuts)
@@ -349,10 +349,10 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
        if self.props.handle_keys {
            match key {
                Key::Esc | Key::Ctrl('c') => {
-
                    let _ = self.send(Action::Exit { selection: None });
+
                    let _ = self.send(Message::Exit { selection: None });
                }
                Key::Char('?') => {
-
                    let _ = self.send(Action::OpenHelp);
+
                    let _ = self.send(Message::OpenHelp);
                }
                _ => {}
            }
@@ -383,15 +383,15 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
            .render(frame, RenderProps::from(shortcuts_area));

        if page_size != self.props.page_size {
-
            let _ = self.send(Action::BrowserPageSize(page_size));
+
            let _ = self.send(Message::BrowserPageSize(page_size));
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -402,7 +402,7 @@ impl Properties for SearchProps {}

pub struct Search {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    _props: SearchProps,
    /// Search input field
@@ -410,23 +410,23 @@ pub struct Search {
}

impl Widget for Search {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self
    where
        Self: Sized,
    {
        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            _props: SearchProps {},
-
            input: TextField::new(state, action_tx.clone())
+
            input: TextField::new(state, tx.clone())
                .on_event(|widget| {
                    widget
-
                        .downcast_mut::<TextField<State, Action>>()
+
                        .downcast_mut::<TextField<State, Message>>()
                        .and_then(|field| {
                            field
-
                                .send(Action::UpdateSearch {
+
                                .send(Message::UpdateSearch {
                                    value: field.text().unwrap_or(&String::new()).to_string(),
                                })
                                .ok()
@@ -446,10 +446,10 @@ impl Widget for Search {
    fn handle_event(&mut self, key: termion::event::Key) {
        match key {
            Key::Esc => {
-
                let _ = self.send(Action::CloseSearch);
+
                let _ = self.send(Message::CloseSearch);
            }
            Key::Char('\n') => {
-
                let _ = self.send(Action::ApplySearch);
+
                let _ = self.send(Message::ApplySearch);
            }
            _ => {
                self.input.handle_event(key);
@@ -469,11 +469,11 @@ impl Widget for Search {
        self.input.render(frame, RenderProps::from(layout[0]));
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -503,7 +503,7 @@ impl<'a> BoxedAny for HelpPageProps<'a> {}

pub struct HelpPage<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: HelpPageProps<'a>,
    /// Content widget
@@ -513,19 +513,19 @@ pub struct HelpPage<'a> {
}

impl<'a: 'static> Widget for HelpPage<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self
    where
        Self: Sized,
    {
        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: HelpPageProps::from(state),
-
            content: Container::new(state, action_tx.clone())
+
            content: Container::new(state, tx.clone())
                .header(
-
                    Header::new(state, action_tx.clone())
+
                    Header::new(state, tx.clone())
                        .on_update(|_| {
                            HeaderProps::default()
                                .columns([Column::new(" Help ", Constraint::Fill(1))].to_vec())
@@ -534,13 +534,13 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .content(
-
                    Paragraph::new(state, action_tx.clone())
+
                    Paragraph::new(state, tx.clone())
                        .on_event(|paragraph| {
                            paragraph
-
                                .downcast_mut::<Paragraph<'_, State, Action>>()
+
                                .downcast_mut::<Paragraph<'_, State, Message>>()
                                .and_then(|paragraph| {
                                    paragraph
-
                                        .send(Action::ScrollHelp {
+
                                        .send(Message::ScrollHelp {
                                            progress: paragraph.progress(),
                                        })
                                        .ok()
@@ -557,7 +557,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .footer(
-
                    Footer::new(state, action_tx.clone())
+
                    Footer::new(state, tx.clone())
                        .on_update(|state| {
                            let props = HelpPageProps::from(state);

@@ -578,7 +578,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .to_boxed(),
-
            shortcuts: Shortcuts::new(state, action_tx.clone())
+
            shortcuts: Shortcuts::new(state, tx.clone())
                .on_update(|state| {
                    ShortcutsProps::default()
                        .shortcuts(&HelpPageProps::from(state).shortcuts)
@@ -591,10 +591,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
    fn handle_event(&mut self, key: termion::event::Key) {
        match key {
            Key::Esc | Key::Ctrl('c') => {
-
                let _ = self.send(Action::Exit { selection: None });
+
                let _ = self.send(Message::Exit { selection: None });
            }
            Key::Char('?') => {
-
                let _ = self.send(Action::LeavePage);
+
                let _ = self.send(Message::LeavePage);
            }
            _ => {
                self.content.handle_event(key);
@@ -622,15 +622,15 @@ impl<'a: 'static> Widget for HelpPage<'a> {
            .render(frame, RenderProps::from(shortcuts_area));

        if page_size != self.props.page_size {
-
            let _ = self.send(Action::HelpPageSize(page_size));
+
            let _ = self.send(Message::HelpPageSize(page_size));
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
modified bin/commands/issue/select.rs
@@ -114,7 +114,7 @@ impl TryFrom<&Context> for State {
    }
}

-
pub enum Action {
+
pub enum Message {
    Exit { selection: Option<Selection> },
    Select { selected: Option<usize> },
    BrowserPageSize(usize),
@@ -129,40 +129,40 @@ pub enum Action {
}

impl store::State<Selection> for State {
-
    type Action = Action;
+
    type Message = Message;

-
    fn handle_action(&mut self, action: Action) -> Option<Exit<Selection>> {
-
        match action {
-
            Action::Exit { selection } => Some(Exit { value: selection }),
-
            Action::Select { selected } => {
+
    fn update(&mut self, message: Message) -> Option<Exit<Selection>> {
+
        match message {
+
            Message::Exit { selection } => Some(Exit { value: selection }),
+
            Message::Select { selected } => {
                self.browser.selected = selected;
                None
            }
-
            Action::BrowserPageSize(size) => {
+
            Message::BrowserPageSize(size) => {
                self.browser.page_size = size;
                None
            }
-
            Action::HelpPageSize(size) => {
+
            Message::HelpPageSize(size) => {
                self.help.page_size = size;
                None
            }
-
            Action::OpenSearch => {
+
            Message::OpenSearch => {
                self.browser.show_search = true;
                None
            }
-
            Action::UpdateSearch { value } => {
+
            Message::UpdateSearch { value } => {
                self.browser.search.write(value);
                self.browser.filter =
                    IssueItemFilter::from_str(&self.browser.search.read()).unwrap_or_default();

                None
            }
-
            Action::ApplySearch => {
+
            Message::ApplySearch => {
                self.browser.search.apply();
                self.browser.show_search = false;
                None
            }
-
            Action::CloseSearch => {
+
            Message::CloseSearch => {
                self.browser.search.reset();
                self.browser.show_search = false;
                self.browser.filter =
@@ -170,15 +170,15 @@ impl store::State<Selection> for State {

                None
            }
-
            Action::OpenHelp => {
+
            Message::OpenHelp => {
                self.pages.push(Page::Help);
                None
            }
-
            Action::LeavePage => {
+
            Message::LeavePage => {
                self.pages.pop();
                None
            }
-
            Action::ScrollHelp { progress } => {
+
            Message::ScrollHelp { progress } => {
                self.help.progress = progress;
                None
            }
@@ -196,7 +196,7 @@ impl App {
    pub async fn run(&self) -> Result<Option<Selection>> {
        let channel = Channel::default();
        let state = State::try_from(&self.context)?;
-
        let window: Window<State, Action, Page> = Window::new(&state, channel.tx.clone())
+
        let window: Window<State, Message, Page> = Window::new(&state, channel.tx.clone())
            .page(
                Page::Browse,
                BrowserPage::new(&state, channel.tx.clone()).to_boxed(),
modified bin/commands/issue/select/ui.rs
@@ -31,9 +31,9 @@ use tui::Selection;
use crate::tui_issue::common::IssueOperation;
use crate::tui_issue::common::Mode;

-
use super::{Action, State};
+
use super::{Message, State};

-
type BoxedWidget = widget::BoxedWidget<State, Action>;
+
type BoxedWidget = widget::BoxedWidget<State, Message>;

#[derive(Clone)]
struct BrowserProps<'a> {
@@ -133,7 +133,7 @@ impl<'a> BoxedAny for BrowserProps<'a> {}

pub struct Browser<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: BrowserProps<'a>,
    /// Notifications widget
@@ -143,30 +143,30 @@ pub struct Browser<'a> {
}

impl<'a: 'static> Widget for Browser<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self {
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self {
        let props = BrowserProps::from(state);

        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: BrowserProps::from(state),
-
            issues: Container::new(state, action_tx.clone())
+
            issues: Container::new(state, tx.clone())
                .header(
-
                    Header::new(state, action_tx.clone())
+
                    Header::new(state, tx.clone())
                        .columns(props.header.clone())
                        .cutoff(props.cutoff, props.cutoff_after)
                        .to_boxed(),
                )
-
                .content(Box::<Table<State, Action, IssueItem, 8>>::new(
-
                    Table::new(state, action_tx.clone())
+
                .content(Box::<Table<State, Message, IssueItem, 8>>::new(
+
                    Table::new(state, tx.clone())
                        .on_event(|table| {
                            table
-
                                .downcast_mut::<Table<State, Action, IssueItem, 8>>()
+
                                .downcast_mut::<Table<State, Message, IssueItem, 8>>()
                                .and_then(|table| {
                                    table
-
                                        .send(Action::Select {
+
                                        .send(Message::Select {
                                            selected: table.selected(),
                                        })
                                        .ok()
@@ -185,7 +185,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        }),
                ))
                .footer(
-
                    Footer::new(state, action_tx.clone())
+
                    Footer::new(state, tx.clone())
                        .on_update(|state| {
                            let props = BrowserProps::from(state);

@@ -201,7 +201,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .to_boxed()
                })
                .to_boxed(),
-
            search: Search::new(state, action_tx.clone()).to_boxed(),
+
            search: Search::new(state, tx.clone()).to_boxed(),
        }
    }

@@ -211,7 +211,7 @@ impl<'a: 'static> Widget for Browser<'a> {
        } else {
            match key {
                Key::Char('/') => {
-
                    let _ = self.send(Action::OpenSearch);
+
                    let _ = self.send(Message::OpenSearch);
                }
                Key::Char('\n') => {
                    let operation = match self.props.mode {
@@ -224,7 +224,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .and_then(|selected| self.props.issues.get(selected))
                        .and_then(|issue| {
                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(Selection {
                                        operation,
                                        ids: vec![issue.id],
@@ -240,7 +240,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .and_then(|selected| self.props.issues.get(selected))
                        .and_then(|issue| {
                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(Selection {
                                        operation: Some(IssueOperation::Edit.to_string()),
                                        ids: vec![issue.id],
@@ -278,11 +278,11 @@ impl<'a: 'static> Widget for Browser<'a> {
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -324,7 +324,7 @@ impl<'a> BoxedAny for BrowserPageProps<'a> {}

pub struct BrowserPage<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: BrowserPageProps<'a>,
    /// Sections widget
@@ -334,17 +334,17 @@ pub struct BrowserPage<'a> {
}

impl<'a: 'static> Widget for BrowserPage<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self {
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self {
        let props = BrowserPageProps::from(state);

        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: props.clone(),
-
            sections: SectionGroup::new(state, action_tx.clone())
-
                .section(Browser::new(state, action_tx.clone()).to_boxed())
+
            sections: SectionGroup::new(state, tx.clone())
+
                .section(Browser::new(state, tx.clone()).to_boxed())
                .on_update(|state| {
                    let props = BrowserPageProps::from(state);
                    SectionGroupProps::default()
@@ -352,7 +352,7 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
                        .to_boxed()
                })
                .to_boxed(),
-
            shortcuts: Shortcuts::new(state, action_tx.clone())
+
            shortcuts: Shortcuts::new(state, tx.clone())
                .on_update(|state| {
                    ShortcutsProps::default()
                        .shortcuts(&BrowserPageProps::from(state).shortcuts)
@@ -368,10 +368,10 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
        if self.props.handle_keys {
            match key {
                Key::Esc | Key::Ctrl('c') => {
-
                    let _ = self.send(Action::Exit { selection: None });
+
                    let _ = self.send(Message::Exit { selection: None });
                }
                Key::Char('?') => {
-
                    let _ = self.send(Action::OpenHelp);
+
                    let _ = self.send(Message::OpenHelp);
                }
                _ => {}
            }
@@ -402,15 +402,15 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
            .render(frame, RenderProps::from(shortcuts_area));

        if page_size != self.props.page_size {
-
            let _ = self.send(Action::BrowserPageSize(page_size));
+
            let _ = self.send(Message::BrowserPageSize(page_size));
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -421,7 +421,7 @@ impl Properties for SearchProps {}

pub struct Search {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    _props: SearchProps,
    /// Search input field
@@ -429,23 +429,23 @@ pub struct Search {
}

impl Widget for Search {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self
    where
        Self: Sized,
    {
        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            _props: SearchProps {},
-
            input: TextField::new(state, action_tx.clone())
+
            input: TextField::new(state, tx.clone())
                .on_event(|widget| {
                    widget
-
                        .downcast_mut::<TextField<State, Action>>()
+
                        .downcast_mut::<TextField<State, Message>>()
                        .and_then(|field| {
                            field
-
                                .send(Action::UpdateSearch {
+
                                .send(Message::UpdateSearch {
                                    value: field.text().unwrap_or(&String::new()).to_string(),
                                })
                                .ok()
@@ -465,10 +465,10 @@ impl Widget for Search {
    fn handle_event(&mut self, key: termion::event::Key) {
        match key {
            Key::Esc => {
-
                let _ = self.send(Action::CloseSearch);
+
                let _ = self.send(Message::CloseSearch);
            }
            Key::Char('\n') => {
-
                let _ = self.send(Action::ApplySearch);
+
                let _ = self.send(Message::ApplySearch);
            }
            _ => {
                self.input.handle_event(key);
@@ -488,11 +488,11 @@ impl Widget for Search {
        self.input.render(frame, RenderProps::from(layout[0]));
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -519,7 +519,7 @@ impl<'a> BoxedAny for HelpPageProps<'a> {}

pub struct HelpPage<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: HelpPageProps<'a>,
    /// Content widget
@@ -529,19 +529,19 @@ pub struct HelpPage<'a> {
}

impl<'a: 'static> Widget for HelpPage<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self
    where
        Self: Sized,
    {
        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: HelpPageProps::from(state),
-
            content: Container::new(state, action_tx.clone())
+
            content: Container::new(state, tx.clone())
                .header(
-
                    Header::new(state, action_tx.clone())
+
                    Header::new(state, tx.clone())
                        .on_update(|_| {
                            HeaderProps::default()
                                .columns([Column::new(" Help ", Constraint::Fill(1))].to_vec())
@@ -550,13 +550,13 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .content(
-
                    Paragraph::new(state, action_tx.clone())
+
                    Paragraph::new(state, tx.clone())
                        .on_event(|paragraph| {
                            paragraph
-
                                .downcast_mut::<Paragraph<'_, State, Action>>()
+
                                .downcast_mut::<Paragraph<'_, State, Message>>()
                                .and_then(|paragraph| {
                                    paragraph
-
                                        .send(Action::ScrollHelp {
+
                                        .send(Message::ScrollHelp {
                                            progress: paragraph.progress(),
                                        })
                                        .ok()
@@ -573,7 +573,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .footer(
-
                    Footer::new(state, action_tx.clone())
+
                    Footer::new(state, tx.clone())
                        .on_update(|state| {
                            let props = HelpPageProps::from(state);

@@ -594,7 +594,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .to_boxed(),
-
            shortcuts: Shortcuts::new(state, action_tx.clone())
+
            shortcuts: Shortcuts::new(state, tx.clone())
                .on_update(|state| {
                    ShortcutsProps::default()
                        .shortcuts(&HelpPageProps::from(state).shortcuts)
@@ -607,10 +607,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
    fn handle_event(&mut self, key: termion::event::Key) {
        match key {
            Key::Esc | Key::Ctrl('c') => {
-
                let _ = self.send(Action::Exit { selection: None });
+
                let _ = self.send(Message::Exit { selection: None });
            }
            Key::Char('?') => {
-
                let _ = self.send(Action::LeavePage);
+
                let _ = self.send(Message::LeavePage);
            }
            _ => {
                self.content.handle_event(key);
@@ -638,15 +638,15 @@ impl<'a: 'static> Widget for HelpPage<'a> {
            .render(frame, RenderProps::from(shortcuts_area));

        if page_size != self.props.page_size {
-
            let _ = self.send(Action::HelpPageSize(page_size));
+
            let _ = self.send(Message::HelpPageSize(page_size));
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
modified bin/commands/patch/select.rs
@@ -115,7 +115,7 @@ impl TryFrom<&Context> for State {
    }
}

-
pub enum Action {
+
pub enum Message {
    Exit { selection: Option<Selection> },
    Select { selected: Option<usize> },
    BrowserPageSize(usize),
@@ -130,40 +130,40 @@ pub enum Action {
}

impl store::State<Selection> for State {
-
    type Action = Action;
+
    type Message = Message;

-
    fn handle_action(&mut self, action: Action) -> Option<Exit<Selection>> {
-
        match action {
-
            Action::Exit { selection } => Some(Exit { value: selection }),
-
            Action::Select { selected } => {
+
    fn update(&mut self, message: Message) -> Option<Exit<Selection>> {
+
        match message {
+
            Message::Exit { selection } => Some(Exit { value: selection }),
+
            Message::Select { selected } => {
                self.browser.selected = selected;
                None
            }
-
            Action::BrowserPageSize(size) => {
+
            Message::BrowserPageSize(size) => {
                self.browser.page_size = size;
                None
            }
-
            Action::HelpPageSize(size) => {
+
            Message::HelpPageSize(size) => {
                self.help.page_size = size;
                None
            }
-
            Action::OpenSearch => {
+
            Message::OpenSearch => {
                self.browser.show_search = true;
                None
            }
-
            Action::UpdateSearch { value } => {
+
            Message::UpdateSearch { value } => {
                self.browser.search.write(value);
                self.browser.filter =
                    PatchItemFilter::from_str(&self.browser.search.read()).unwrap_or_default();

                None
            }
-
            Action::ApplySearch => {
+
            Message::ApplySearch => {
                self.browser.search.apply();
                self.browser.show_search = false;
                None
            }
-
            Action::CloseSearch => {
+
            Message::CloseSearch => {
                self.browser.search.reset();
                self.browser.show_search = false;
                self.browser.filter =
@@ -171,15 +171,15 @@ impl store::State<Selection> for State {

                None
            }
-
            Action::OpenHelp => {
+
            Message::OpenHelp => {
                self.pages.push(Page::Help);
                None
            }
-
            Action::LeavePage => {
+
            Message::LeavePage => {
                self.pages.pop();
                None
            }
-
            Action::ScrollHelp { progress } => {
+
            Message::ScrollHelp { progress } => {
                self.help.progress = progress;
                None
            }
@@ -197,7 +197,7 @@ impl App {
    pub async fn run(&self) -> Result<Option<Selection>> {
        let channel = Channel::default();
        let state = State::try_from(&self.context)?;
-
        let window: Window<State, Action, Page> = Window::new(&state, channel.tx.clone())
+
        let window: Window<State, Message, Page> = Window::new(&state, channel.tx.clone())
            .page(
                Page::Browse,
                BrowserPage::new(&state, channel.tx.clone()).to_boxed(),
modified bin/commands/patch/select/ui.rs
@@ -32,9 +32,9 @@ use tui::Selection;
use crate::tui_patch::common::Mode;
use crate::tui_patch::common::PatchOperation;

-
use super::{Action, State};
+
use super::{Message, State};

-
type BoxedWidget = widget::BoxedWidget<State, Action>;
+
type BoxedWidget = widget::BoxedWidget<State, Message>;

#[derive(Clone)]
pub struct BrowserProps<'a> {
@@ -133,7 +133,7 @@ impl<'a: 'static> BoxedAny for BrowserProps<'a> {}

pub struct Browser<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: BrowserProps<'a>,
    /// Patches widget
@@ -143,30 +143,30 @@ pub struct Browser<'a> {
}

impl<'a: 'static> Widget for Browser<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self {
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self {
        let props = BrowserProps::from(state);

        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: props.clone(),
-
            patches: Container::new(state, action_tx.clone())
+
            patches: Container::new(state, tx.clone())
                .header(
-
                    Header::new(state, action_tx.clone())
+
                    Header::new(state, tx.clone())
                        .columns(props.header.clone())
                        .cutoff(props.cutoff, props.cutoff_after)
                        .to_boxed(),
                )
-
                .content(Box::<Table<State, Action, PatchItem, 9>>::new(
-
                    Table::new(state, action_tx.clone())
+
                .content(Box::<Table<State, Message, PatchItem, 9>>::new(
+
                    Table::new(state, tx.clone())
                        .on_event(|table| {
                            table
-
                                .downcast_mut::<Table<State, Action, PatchItem, 9>>()
+
                                .downcast_mut::<Table<State, Message, PatchItem, 9>>()
                                .and_then(|table| {
                                    table
-
                                        .send(Action::Select {
+
                                        .send(Message::Select {
                                            selected: table.selected(),
                                        })
                                        .ok()
@@ -185,7 +185,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        }),
                ))
                .footer(
-
                    Footer::new(state, action_tx.clone())
+
                    Footer::new(state, tx.clone())
                        .on_update(|state| {
                            let props = BrowserProps::from(state);

@@ -201,7 +201,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .to_boxed()
                })
                .to_boxed(),
-
            search: Search::new(state, action_tx.clone()).to_boxed(),
+
            search: Search::new(state, tx.clone()).to_boxed(),
        }
    }

@@ -211,13 +211,13 @@ impl<'a: 'static> Widget for Browser<'a> {
        } else {
            match key {
                Key::Esc | Key::Ctrl('c') => {
-
                    let _ = self.send(Action::Exit { selection: None });
+
                    let _ = self.send(Message::Exit { selection: None });
                }
                Key::Char('?') => {
-
                    let _ = self.send(Action::OpenHelp);
+
                    let _ = self.send(Message::OpenHelp);
                }
                Key::Char('/') => {
-
                    let _ = self.send(Action::OpenSearch);
+
                    let _ = self.send(Message::OpenSearch);
                }
                Key::Char('\n') => {
                    let operation = match self.props.mode {
@@ -230,7 +230,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .and_then(|selected| self.props.patches.get(selected))
                        .and_then(|patch| {
                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(Selection {
                                        operation,
                                        ids: vec![patch.id],
@@ -246,7 +246,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .and_then(|selected| self.props.patches.get(selected))
                        .and_then(|patch| {
                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(Selection {
                                        operation: Some(PatchOperation::Checkout.to_string()),
                                        ids: vec![patch.id],
@@ -262,7 +262,7 @@ impl<'a: 'static> Widget for Browser<'a> {
                        .and_then(|selected| self.props.patches.get(selected))
                        .and_then(|patch| {
                            self.base
-
                                .send(Action::Exit {
+
                                .send(Message::Exit {
                                    selection: Some(Selection {
                                        operation: Some(PatchOperation::Diff.to_string()),
                                        ids: vec![patch.id],
@@ -300,11 +300,11 @@ impl<'a: 'static> Widget for Browser<'a> {
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -347,7 +347,7 @@ impl<'a> BoxedAny for BrowserPageProps<'a> {}

pub struct BrowserPage<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: BrowserPageProps<'a>,
    /// Sections widget
@@ -357,17 +357,17 @@ pub struct BrowserPage<'a> {
}

impl<'a: 'static> Widget for BrowserPage<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self {
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self {
        let props = BrowserPageProps::from(state);

        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: props.clone(),
-
            sections: SectionGroup::new(state, action_tx.clone())
-
                .section(Browser::new(state, action_tx.clone()).to_boxed())
+
            sections: SectionGroup::new(state, tx.clone())
+
                .section(Browser::new(state, tx.clone()).to_boxed())
                .on_update(|state| {
                    let props = BrowserPageProps::from(state);
                    SectionGroupProps::default()
@@ -375,7 +375,7 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
                        .to_boxed()
                })
                .to_boxed(),
-
            shortcuts: Shortcuts::new(state, action_tx.clone())
+
            shortcuts: Shortcuts::new(state, tx.clone())
                .on_update(|state| {
                    ShortcutsProps::default()
                        .shortcuts(&BrowserPageProps::from(state).shortcuts)
@@ -391,10 +391,10 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
        if self.props.handle_keys {
            match key {
                Key::Esc | Key::Ctrl('c') => {
-
                    let _ = self.send(Action::Exit { selection: None });
+
                    let _ = self.send(Message::Exit { selection: None });
                }
                Key::Char('?') => {
-
                    let _ = self.send(Action::OpenHelp);
+
                    let _ = self.send(Message::OpenHelp);
                }
                _ => {}
            }
@@ -425,15 +425,15 @@ impl<'a: 'static> Widget for BrowserPage<'a> {
            .render(frame, RenderProps::from(shortcuts_area));

        if page_size != self.props.page_size {
-
            let _ = self.send(Action::BrowserPageSize(page_size));
+
            let _ = self.send(Message::BrowserPageSize(page_size));
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -444,7 +444,7 @@ impl Properties for SearchProps {}

pub struct Search {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    _props: SearchProps,
    /// Search input field
@@ -452,23 +452,23 @@ pub struct Search {
}

impl Widget for Search {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self
    where
        Self: Sized,
    {
        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            _props: SearchProps {},
-
            input: TextField::new(state, action_tx.clone())
+
            input: TextField::new(state, tx.clone())
                .on_event(|widget| {
                    widget
-
                        .downcast_mut::<TextField<State, Action>>()
+
                        .downcast_mut::<TextField<State, Message>>()
                        .and_then(|field| {
                            field
-
                                .send(Action::UpdateSearch {
+
                                .send(Message::UpdateSearch {
                                    value: field.text().unwrap_or(&String::new()).to_string(),
                                })
                                .ok()
@@ -488,10 +488,10 @@ impl Widget for Search {
    fn handle_event(&mut self, key: termion::event::Key) {
        match key {
            Key::Esc => {
-
                let _ = self.send(Action::CloseSearch);
+
                let _ = self.send(Message::CloseSearch);
            }
            Key::Char('\n') => {
-
                let _ = self.send(Action::ApplySearch);
+
                let _ = self.send(Message::ApplySearch);
            }
            _ => {
                self.input.handle_event(key);
@@ -511,11 +511,11 @@ impl Widget for Search {
        self.input.render(frame, RenderProps::from(layout[0]));
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}
@@ -542,7 +542,7 @@ impl<'a> BoxedAny for HelpPageProps<'a> {}

pub struct HelpPage<'a> {
    /// Internal base
-
    base: WidgetBase<State, Action>,
+
    base: WidgetBase<State, Message>,
    /// Internal props
    props: HelpPageProps<'a>,
    /// Content widget
@@ -552,19 +552,19 @@ pub struct HelpPage<'a> {
}

impl<'a: 'static> Widget for HelpPage<'a> {
-
    type Action = Action;
+
    type Message = Message;
    type State = State;

-
    fn new(state: &State, action_tx: UnboundedSender<Action>) -> Self
+
    fn new(state: &State, tx: UnboundedSender<Message>) -> Self
    where
        Self: Sized,
    {
        Self {
-
            base: WidgetBase::new(action_tx.clone()),
+
            base: WidgetBase::new(tx.clone()),
            props: HelpPageProps::from(state),
-
            content: Container::new(state, action_tx.clone())
+
            content: Container::new(state, tx.clone())
                .header(
-
                    Header::new(state, action_tx.clone())
+
                    Header::new(state, tx.clone())
                        .on_update(|_| {
                            HeaderProps::default()
                                .columns([Column::new(" Help ", Constraint::Fill(1))].to_vec())
@@ -573,13 +573,13 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .content(
-
                    Paragraph::new(state, action_tx.clone())
+
                    Paragraph::new(state, tx.clone())
                        .on_event(|paragraph| {
                            paragraph
-
                                .downcast_mut::<Paragraph<'_, State, Action>>()
+
                                .downcast_mut::<Paragraph<'_, State, Message>>()
                                .and_then(|paragraph| {
                                    paragraph
-
                                        .send(Action::ScrollHelp {
+
                                        .send(Message::ScrollHelp {
                                            progress: paragraph.progress(),
                                        })
                                        .ok()
@@ -596,7 +596,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .footer(
-
                    Footer::new(state, action_tx.clone())
+
                    Footer::new(state, tx.clone())
                        .on_update(|state| {
                            let props = HelpPageProps::from(state);

@@ -617,7 +617,7 @@ impl<'a: 'static> Widget for HelpPage<'a> {
                        .to_boxed(),
                )
                .to_boxed(),
-
            shortcuts: Shortcuts::new(state, action_tx.clone())
+
            shortcuts: Shortcuts::new(state, tx.clone())
                .on_update(|state| {
                    ShortcutsProps::default()
                        .shortcuts(&HelpPageProps::from(state).shortcuts)
@@ -630,10 +630,10 @@ impl<'a: 'static> Widget for HelpPage<'a> {
    fn handle_event(&mut self, key: termion::event::Key) {
        match key {
            Key::Esc | Key::Ctrl('c') => {
-
                let _ = self.send(Action::Exit { selection: None });
+
                let _ = self.send(Message::Exit { selection: None });
            }
            Key::Char('?') => {
-
                let _ = self.send(Action::LeavePage);
+
                let _ = self.send(Message::LeavePage);
            }
            _ => {
                self.content.handle_event(key);
@@ -660,15 +660,15 @@ impl<'a: 'static> Widget for HelpPage<'a> {
            .render(frame, RenderProps::from(shortcuts_area));

        if page_size != self.props.page_size {
-
            let _ = self.send(Action::HelpPageSize(page_size));
+
            let _ = self.send(Message::HelpPageSize(page_size));
        }
    }

-
    fn base(&self) -> &WidgetBase<State, Action> {
+
    fn base(&self) -> &WidgetBase<State, Message> {
        &self.base
    }

-
    fn base_mut(&mut self) -> &mut WidgetBase<State, Action> {
+
    fn base_mut(&mut self) -> &mut WidgetBase<State, Message> {
        &mut self.base
    }
}