275 lines
7.7 KiB
Rust
275 lines
7.7 KiB
Rust
use tuirealm::command::{Cmd, CmdResult};
|
|
use tuirealm::tui::layout::Rect;
|
|
use tuirealm::{AttrValue, Attribute, Frame, MockComponent, Props, State};
|
|
|
|
use super::common;
|
|
use super::common::container::{LabeledContainer, Tabs};
|
|
use super::common::context::Shortcuts;
|
|
use super::common::list::{ColumnWidth, Table};
|
|
|
|
use super::{Widget, WidgetComponent};
|
|
|
|
use crate::cob;
|
|
use crate::ui::cob::{IssueItem, PatchItem};
|
|
use crate::ui::context::Context;
|
|
use crate::ui::layout;
|
|
use crate::ui::theme::Theme;
|
|
|
|
pub struct Dashboard {
|
|
about: Widget<LabeledContainer>,
|
|
shortcuts: Widget<Shortcuts>,
|
|
}
|
|
|
|
impl Dashboard {
|
|
pub fn new(about: Widget<LabeledContainer>, shortcuts: Widget<Shortcuts>) -> Self {
|
|
Self { about, shortcuts }
|
|
}
|
|
}
|
|
|
|
impl WidgetComponent for Dashboard {
|
|
fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
|
|
let shortcuts_h = self
|
|
.shortcuts
|
|
.query(Attribute::Height)
|
|
.unwrap_or(AttrValue::Size(0))
|
|
.unwrap_size();
|
|
let layout = layout::root_component(area, shortcuts_h);
|
|
|
|
self.about.view(frame, layout[0]);
|
|
self.shortcuts.view(frame, layout[1]);
|
|
}
|
|
|
|
fn state(&self) -> State {
|
|
State::None
|
|
}
|
|
|
|
fn perform(&mut self, _properties: &Props, _cmd: Cmd) -> CmdResult {
|
|
CmdResult::None
|
|
}
|
|
}
|
|
|
|
pub struct IssueBrowser {
|
|
items: Vec<IssueItem>,
|
|
table: Widget<Table<IssueItem, 7>>,
|
|
shortcuts: Widget<Shortcuts>,
|
|
}
|
|
|
|
impl IssueBrowser {
|
|
pub fn new(context: &Context, theme: &Theme, shortcuts: Widget<Shortcuts>) -> Self {
|
|
let header = [
|
|
common::label(" ● "),
|
|
common::label("ID"),
|
|
common::label("Title"),
|
|
common::label("Author"),
|
|
common::label("Tags"),
|
|
common::label("Assignees"),
|
|
common::label("Opened"),
|
|
];
|
|
|
|
let widths = [
|
|
ColumnWidth::Fixed(3),
|
|
ColumnWidth::Fixed(7),
|
|
ColumnWidth::Grow,
|
|
ColumnWidth::Fixed(21),
|
|
ColumnWidth::Fixed(25),
|
|
ColumnWidth::Fixed(21),
|
|
ColumnWidth::Fixed(18),
|
|
];
|
|
|
|
let repo = context.repository();
|
|
let mut items = vec![];
|
|
|
|
if let Ok(issues) = cob::issue::all(repo) {
|
|
for (id, issue) in issues {
|
|
if let Ok(item) = IssueItem::try_from((context.profile(), repo, id, issue)) {
|
|
items.push(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
items.sort_by(|a, b| b.timestamp().cmp(a.timestamp()));
|
|
items.sort_by(|a, b| b.state().cmp(a.state()));
|
|
|
|
let table = Widget::new(Table::new(&items, header, widths, theme.clone()))
|
|
.highlight(theme.colors.item_list_highlighted_bg);
|
|
|
|
Self {
|
|
items,
|
|
table,
|
|
shortcuts,
|
|
}
|
|
}
|
|
|
|
pub fn items(&self) -> &Vec<IssueItem> {
|
|
&self.items
|
|
}
|
|
}
|
|
|
|
impl WidgetComponent for IssueBrowser {
|
|
fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
|
|
let shortcuts_h = self
|
|
.shortcuts
|
|
.query(Attribute::Height)
|
|
.unwrap_or(AttrValue::Size(0))
|
|
.unwrap_size();
|
|
let layout = layout::root_component(area, shortcuts_h);
|
|
|
|
self.table.view(frame, layout[0]);
|
|
self.shortcuts.view(frame, layout[1])
|
|
}
|
|
|
|
fn state(&self) -> State {
|
|
self.table.state()
|
|
}
|
|
|
|
fn perform(&mut self, _properties: &Props, cmd: Cmd) -> CmdResult {
|
|
self.table.perform(cmd)
|
|
}
|
|
}
|
|
|
|
pub struct PatchBrowser {
|
|
items: Vec<PatchItem>,
|
|
table: Widget<Table<PatchItem, 8>>,
|
|
shortcuts: Widget<Shortcuts>,
|
|
}
|
|
|
|
impl PatchBrowser {
|
|
pub fn new(context: &Context, theme: &Theme, shortcuts: Widget<Shortcuts>) -> Self {
|
|
let header = [
|
|
common::label(" ● "),
|
|
common::label("ID"),
|
|
common::label("Title"),
|
|
common::label("Author"),
|
|
common::label("Head"),
|
|
common::label("+"),
|
|
common::label("-"),
|
|
common::label("Updated"),
|
|
];
|
|
|
|
let widths = [
|
|
ColumnWidth::Fixed(3),
|
|
ColumnWidth::Fixed(7),
|
|
ColumnWidth::Grow,
|
|
ColumnWidth::Fixed(21),
|
|
ColumnWidth::Fixed(7),
|
|
ColumnWidth::Fixed(4),
|
|
ColumnWidth::Fixed(4),
|
|
ColumnWidth::Fixed(18),
|
|
];
|
|
|
|
let repo = context.repository();
|
|
let mut items = vec![];
|
|
|
|
if let Ok(patches) = cob::patch::all(repo) {
|
|
for (id, patch) in patches {
|
|
if let Ok(item) = PatchItem::try_from((context.profile(), repo, id, patch)) {
|
|
items.push(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
items.sort_by(|a, b| b.timestamp().cmp(a.timestamp()));
|
|
items.sort_by(|a, b| a.state().cmp(b.state()));
|
|
|
|
let table = Widget::new(Table::new(&items, header, widths, theme.clone()))
|
|
.highlight(theme.colors.item_list_highlighted_bg);
|
|
|
|
Self {
|
|
items,
|
|
table,
|
|
shortcuts,
|
|
}
|
|
}
|
|
|
|
pub fn items(&self) -> &Vec<PatchItem> {
|
|
&self.items
|
|
}
|
|
}
|
|
|
|
impl WidgetComponent for PatchBrowser {
|
|
fn view(&mut self, _properties: &Props, frame: &mut Frame, area: Rect) {
|
|
let shortcuts_h = self
|
|
.shortcuts
|
|
.query(Attribute::Height)
|
|
.unwrap_or(AttrValue::Size(0))
|
|
.unwrap_size();
|
|
let layout = layout::root_component(area, shortcuts_h);
|
|
|
|
self.table.view(frame, layout[0]);
|
|
self.shortcuts.view(frame, layout[1]);
|
|
}
|
|
|
|
fn state(&self) -> State {
|
|
self.table.state()
|
|
}
|
|
|
|
fn perform(&mut self, _properties: &Props, cmd: Cmd) -> CmdResult {
|
|
self.table.perform(cmd)
|
|
}
|
|
}
|
|
|
|
pub fn navigation(theme: &Theme) -> Widget<Tabs> {
|
|
common::tabs(
|
|
theme,
|
|
vec![
|
|
common::reversable_label("dashboard").foreground(theme.colors.tabs_highlighted_fg),
|
|
common::reversable_label("issues").foreground(theme.colors.tabs_highlighted_fg),
|
|
common::reversable_label("patches").foreground(theme.colors.tabs_highlighted_fg),
|
|
],
|
|
)
|
|
}
|
|
|
|
pub fn dashboard(context: &Context, theme: &Theme) -> Widget<Dashboard> {
|
|
let about = common::labeled_container(
|
|
theme,
|
|
"about",
|
|
common::property_list(
|
|
theme,
|
|
vec![
|
|
common::property(theme, "id", &context.id().to_string()),
|
|
common::property(theme, "name", context.project().name()),
|
|
common::property(theme, "description", context.project().description()),
|
|
],
|
|
)
|
|
.to_boxed(),
|
|
);
|
|
let shortcuts = common::shortcuts(
|
|
theme,
|
|
vec![
|
|
common::shortcut(theme, "tab", "section"),
|
|
common::shortcut(theme, "q", "quit"),
|
|
],
|
|
);
|
|
let dashboard = Dashboard::new(about, shortcuts);
|
|
|
|
Widget::new(dashboard)
|
|
}
|
|
|
|
pub fn patches(context: &Context, theme: &Theme) -> Widget<PatchBrowser> {
|
|
let shortcuts = common::shortcuts(
|
|
theme,
|
|
vec![
|
|
common::shortcut(theme, "tab", "section"),
|
|
common::shortcut(theme, "↑/↓", "navigate"),
|
|
common::shortcut(theme, "enter", "show"),
|
|
common::shortcut(theme, "q", "quit"),
|
|
],
|
|
);
|
|
|
|
Widget::new(PatchBrowser::new(context, theme, shortcuts))
|
|
}
|
|
|
|
pub fn issues(context: &Context, theme: &Theme) -> Widget<IssueBrowser> {
|
|
let shortcuts = common::shortcuts(
|
|
theme,
|
|
vec![
|
|
common::shortcut(theme, "tab", "section"),
|
|
common::shortcut(theme, "↑/↓", "navigate"),
|
|
common::shortcut(theme, "enter", "show"),
|
|
common::shortcut(theme, "q", "quit"),
|
|
],
|
|
);
|
|
|
|
Widget::new(IssueBrowser::new(context, theme, shortcuts))
|
|
}
|