refactor: Improve error handling and remove code duplication
Extract duplicate UI update logic from reload_tasks and handle_sync into a shared update_ui_from_tasks method. Add error notifications to StatusBar so users can see when task loading fails instead of silently showing an empty list. Fix sidebar to only show pending tasks, filtering out deleted and completed ones. Move magic numbers to constants in ui.rs (sidebar width, table column widths, date format) to make layout adjustments easier. Standardize all date formatting to ISO 8601 (YYYY-MM-DD) for consistency across the app.
This commit is contained in:
+28
-29
@@ -3,9 +3,9 @@ use std::collections::HashMap;
|
|||||||
use gpui::prelude::*;
|
use gpui::prelude::*;
|
||||||
|
|
||||||
use crate::models::{FilterState, ProjectTree};
|
use crate::models::{FilterState, ProjectTree};
|
||||||
use crate::task::{self, TaskFilter, TaskOverview, TaskService};
|
use crate::task::{self, TaskOverview, TaskService};
|
||||||
use crate::theme::ActiveTheme;
|
use crate::theme::ActiveTheme;
|
||||||
use crate::ui::{ROOT_PADDING, SECTION_GAP, card_style};
|
use crate::ui::{ROOT_PADDING, SECTION_GAP, SIDEBAR_WIDTH, card_style};
|
||||||
use crate::view::sidebar::{Sidebar, TagItem};
|
use crate::view::sidebar::{Sidebar, TagItem};
|
||||||
use crate::view::status_bar::{StatusBar, StatusBarEvent, SyncState};
|
use crate::view::status_bar::{StatusBar, StatusBarEvent, SyncState};
|
||||||
use crate::view::task_table::TaskTable;
|
use crate::view::task_table::TaskTable;
|
||||||
@@ -28,7 +28,7 @@ impl gpui::Render for App {
|
|||||||
let theme = cx.theme();
|
let theme = cx.theme();
|
||||||
|
|
||||||
let sidebar = card_style(div(), theme)
|
let sidebar = card_style(div(), theme)
|
||||||
.w(gpui::px(250.))
|
.w(SIDEBAR_WIDTH)
|
||||||
.h_full()
|
.h_full()
|
||||||
.flex_shrink_0()
|
.flex_shrink_0()
|
||||||
.overflow_hidden()
|
.overflow_hidden()
|
||||||
@@ -68,6 +68,10 @@ impl App {
|
|||||||
let mut tag_counts: HashMap<String, usize> = HashMap::new();
|
let mut tag_counts: HashMap<String, usize> = HashMap::new();
|
||||||
|
|
||||||
for task in tasks {
|
for task in tasks {
|
||||||
|
if !matches!(task.status, task::TaskStatus::Pending) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(project) = &task.project {
|
if let Some(project) = &task.project {
|
||||||
*project_counts.entry(project.clone()).or_insert(0) += 1;
|
*project_counts.entry(project.clone()).or_insert(0) += 1;
|
||||||
}
|
}
|
||||||
@@ -91,16 +95,8 @@ impl App {
|
|||||||
(projects, tag_items)
|
(projects, tag_items)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reload_tasks(&mut self, cx: &mut gpui::Context<Self>) {
|
fn update_ui_from_tasks(&mut self, all_tasks: Vec<task::Task>, cx: &mut gpui::Context<Self>) {
|
||||||
let all_tasks = self.task_service.get_all_tasks().unwrap_or_else(|e| {
|
let (projects, tags) = Self::build_sidebar_data(&all_tasks);
|
||||||
log::error!("[App] Failed to load tasks: {}", e);
|
|
||||||
vec![]
|
|
||||||
});
|
|
||||||
|
|
||||||
let filter_state = self.filter_state.read(cx).clone();
|
|
||||||
let task_filter = TaskFilter::from(&filter_state);
|
|
||||||
let filtered_tasks = task_filter.apply(&all_tasks);
|
|
||||||
let (projects, tags) = Self::build_sidebar_data(&filtered_tasks);
|
|
||||||
|
|
||||||
let mut project_tree = ProjectTree::new();
|
let mut project_tree = ProjectTree::new();
|
||||||
project_tree.build_from_projects(&projects);
|
project_tree.build_from_projects(&projects);
|
||||||
@@ -115,6 +111,24 @@ impl App {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reload_tasks(&mut self, cx: &mut gpui::Context<Self>) {
|
||||||
|
match self.task_service.get_all_tasks() {
|
||||||
|
Ok(all_tasks) => {
|
||||||
|
self.status_bar.update(cx, |bar, cx| {
|
||||||
|
bar.clear_error(cx);
|
||||||
|
});
|
||||||
|
self.update_ui_from_tasks(all_tasks, cx);
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
log::error!("[App] Failed to load tasks: {}", e);
|
||||||
|
self.status_bar.update(cx, |bar, cx| {
|
||||||
|
bar.set_error(format!("Failed to load tasks: {}", e), cx);
|
||||||
|
});
|
||||||
|
self.update_ui_from_tasks(vec![], cx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn handle_sync(&mut self, cx: &mut gpui::Context<Self>) {
|
fn handle_sync(&mut self, cx: &mut gpui::Context<Self>) {
|
||||||
self.status_bar.update(cx, |bar, cx| {
|
self.status_bar.update(cx, |bar, cx| {
|
||||||
bar.set_sync_state(SyncState::Syncing, cx);
|
bar.set_sync_state(SyncState::Syncing, cx);
|
||||||
@@ -123,22 +137,7 @@ impl App {
|
|||||||
|
|
||||||
match self.task_service.get_all_tasks() {
|
match self.task_service.get_all_tasks() {
|
||||||
Ok(all_tasks) => {
|
Ok(all_tasks) => {
|
||||||
let filter_state = self.filter_state.read(cx).clone();
|
self.update_ui_from_tasks(all_tasks, cx);
|
||||||
let task_filter = TaskFilter::from(&filter_state);
|
|
||||||
let filtered_tasks = task_filter.apply(&all_tasks);
|
|
||||||
let (projects, tags) = Self::build_sidebar_data(&filtered_tasks);
|
|
||||||
|
|
||||||
let mut project_tree = ProjectTree::new();
|
|
||||||
project_tree.build_from_projects(&projects);
|
|
||||||
|
|
||||||
self.sidebar.update(cx, |sidebar, cx| {
|
|
||||||
sidebar.update_projects(project_tree, cx);
|
|
||||||
sidebar.update_tags(tags, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.task_table.update(cx, |table, cx| {
|
|
||||||
table.reload_tasks_from_all(all_tasks, cx);
|
|
||||||
});
|
|
||||||
|
|
||||||
self.status_bar.update(cx, |bar, cx| {
|
self.status_bar.update(cx, |bar, cx| {
|
||||||
bar.set_sync_state(SyncState::Success, cx);
|
bar.set_sync_state(SyncState::Success, cx);
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use std::collections::HashSet;
|
|||||||
|
|
||||||
use chrono::NaiveDate;
|
use chrono::NaiveDate;
|
||||||
|
|
||||||
|
use crate::ui::DATE_FORMAT;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub struct FilterState {
|
pub struct FilterState {
|
||||||
pub selected_project: Option<String>,
|
pub selected_project: Option<String>,
|
||||||
@@ -147,7 +149,7 @@ impl DueFilter {
|
|||||||
Self::Today => "Today".to_string(),
|
Self::Today => "Today".to_string(),
|
||||||
Self::ThisWeek => "This Week".to_string(),
|
Self::ThisWeek => "This Week".to_string(),
|
||||||
Self::NoDate => "No Date".to_string(),
|
Self::NoDate => "No Date".to_string(),
|
||||||
Self::OnDate(date) => date.format("%d-%m-%Y").to_string(),
|
Self::OnDate(date) => date.format(DATE_FORMAT).to_string(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +160,7 @@ impl DueFilter {
|
|||||||
Self::Today => "today".to_string(),
|
Self::Today => "today".to_string(),
|
||||||
Self::ThisWeek => "this_week".to_string(),
|
Self::ThisWeek => "this_week".to_string(),
|
||||||
Self::NoDate => "none".to_string(),
|
Self::NoDate => "none".to_string(),
|
||||||
Self::OnDate(date) => format!("date:{}", date.format("%Y-%m-%d")),
|
Self::OnDate(date) => format!("date:{}", date.format(DATE_FORMAT)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use gpui::prelude::*;
|
use gpui::prelude::*;
|
||||||
use gpui::{Pixels, px};
|
use gpui::{Pixels, px, rems};
|
||||||
|
|
||||||
use crate::theme::Theme;
|
use crate::theme::Theme;
|
||||||
|
|
||||||
@@ -11,6 +11,43 @@ pub const ROOT_PADDING: Pixels = px(12.0);
|
|||||||
pub const CONTROL_RADIUS: Pixels = px(6.0);
|
pub const CONTROL_RADIUS: Pixels = px(6.0);
|
||||||
pub const CONTROL_BORDER: Pixels = px(1.0);
|
pub const CONTROL_BORDER: Pixels = px(1.0);
|
||||||
|
|
||||||
|
pub const SIDEBAR_WIDTH: Pixels = px(250.0);
|
||||||
|
|
||||||
|
pub const TABLE_MAX_DESCRIPTION_LENGTH: usize = 50;
|
||||||
|
pub const TABLE_FILTER_BAR_INITIAL_HEIGHT: Pixels = px(52.0);
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn table_col_id_width() -> gpui::Rems {
|
||||||
|
rems(3.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn table_col_desc_min_width() -> gpui::Rems {
|
||||||
|
rems(10.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn table_col_project_width() -> gpui::Rems {
|
||||||
|
rems(10.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn table_col_due_width() -> gpui::Rems {
|
||||||
|
rems(7.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn table_col_priority_width() -> gpui::Rems {
|
||||||
|
rems(5.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn table_col_status_width() -> gpui::Rems {
|
||||||
|
rems(6.0)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub const DATE_FORMAT: &str = "%Y-%m-%d";
|
||||||
|
|
||||||
pub fn card_style(div: gpui::Div, theme: &Theme) -> gpui::Div {
|
pub fn card_style(div: gpui::Div, theme: &Theme) -> gpui::Div {
|
||||||
div.bg(theme.card)
|
div.bg(theme.card)
|
||||||
.border_1()
|
.border_1()
|
||||||
|
|||||||
+72
-2
@@ -1,7 +1,7 @@
|
|||||||
use gpui::{Context, IntoElement, MouseButton, Render, Window, div, prelude::*, rems};
|
use gpui::{Context, IntoElement, MouseButton, Render, Window, div, prelude::*, rems};
|
||||||
|
|
||||||
use crate::components::label::Label;
|
use crate::components::label::Label;
|
||||||
use crate::theme::ActiveTheme;
|
use crate::theme::{ActiveTheme, Theme};
|
||||||
use crate::ui::divider_v;
|
use crate::ui::divider_v;
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -21,6 +21,7 @@ impl Default for SyncState {
|
|||||||
pub struct StatusBar {
|
pub struct StatusBar {
|
||||||
sync_state: SyncState,
|
sync_state: SyncState,
|
||||||
last_sync_message: String,
|
last_sync_message: String,
|
||||||
|
error_message: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StatusBar {
|
impl StatusBar {
|
||||||
@@ -28,6 +29,7 @@ impl StatusBar {
|
|||||||
Self {
|
Self {
|
||||||
sync_state: SyncState::default(),
|
sync_state: SyncState::default(),
|
||||||
last_sync_message: String::new(),
|
last_sync_message: String::new(),
|
||||||
|
error_message: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -47,6 +49,16 @@ impl StatusBar {
|
|||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_error(&mut self, message: String, cx: &mut Context<Self>) {
|
||||||
|
self.error_message = Some(message);
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_error(&mut self, cx: &mut Context<Self>) {
|
||||||
|
self.error_message = None;
|
||||||
|
cx.notify();
|
||||||
|
}
|
||||||
|
|
||||||
fn sync_icon(&self) -> &'static str {
|
fn sync_icon(&self) -> &'static str {
|
||||||
match self.sync_state {
|
match self.sync_state {
|
||||||
SyncState::Idle => "↻",
|
SyncState::Idle => "↻",
|
||||||
@@ -98,7 +110,52 @@ impl Render for StatusBar {
|
|||||||
Label::new("")
|
Label::new("")
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let error_banner = if let Some(ref error) = self.error_message {
|
||||||
|
Some(
|
||||||
div()
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.justify_between()
|
||||||
|
.w_full()
|
||||||
|
.px_3()
|
||||||
|
.py_2()
|
||||||
|
.bg(Theme::alpha(theme.error, 0.12))
|
||||||
|
.border_1()
|
||||||
|
.border_color(theme.error)
|
||||||
|
.rounded_md()
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.items_center()
|
||||||
|
.gap_2()
|
||||||
|
.child(Label::new("✕").text_color(theme.error).text_sm())
|
||||||
|
.child(
|
||||||
|
Label::new(error.clone())
|
||||||
|
.text_color(theme.error)
|
||||||
|
.text_sm(),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.child(
|
||||||
|
div()
|
||||||
|
.px_2()
|
||||||
|
.py_1()
|
||||||
|
.rounded_sm()
|
||||||
|
.cursor_pointer()
|
||||||
|
.hover(|s| s.bg(Theme::alpha(theme.error, 0.2)))
|
||||||
|
.on_mouse_down(
|
||||||
|
MouseButton::Left,
|
||||||
|
cx.listener(|this, _event, _window, cx| {
|
||||||
|
this.clear_error(cx);
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
.child(Label::new("✕").text_color(theme.error).text_sm()),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
let status_bar_content = div()
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.justify_between()
|
.justify_between()
|
||||||
@@ -124,7 +181,20 @@ impl Render for StatusBar {
|
|||||||
.gap_2()
|
.gap_2()
|
||||||
.child(divider_v(&theme).h(rems(1.0)))
|
.child(divider_v(&theme).h(rems(1.0)))
|
||||||
.child(sync_button),
|
.child(sync_button),
|
||||||
)
|
);
|
||||||
|
|
||||||
|
if let Some(error) = error_banner {
|
||||||
|
div()
|
||||||
|
.flex()
|
||||||
|
.flex_col()
|
||||||
|
.w_full()
|
||||||
|
.gap_2()
|
||||||
|
.p_2()
|
||||||
|
.child(error)
|
||||||
|
.child(status_bar_content)
|
||||||
|
} else {
|
||||||
|
status_bar_content
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+19
-15
@@ -13,7 +13,11 @@ use crate::{
|
|||||||
models::{DueFilter, FilterState, PriorityFilter, StatusFilter},
|
models::{DueFilter, FilterState, PriorityFilter, StatusFilter},
|
||||||
task::{self, TaskFilter, TaskService},
|
task::{self, TaskFilter, TaskService},
|
||||||
theme::{self, ActiveTheme},
|
theme::{self, ActiveTheme},
|
||||||
ui::priority_badge,
|
ui::{
|
||||||
|
priority_badge, table_col_desc_min_width, table_col_due_width, table_col_id_width,
|
||||||
|
table_col_priority_width, table_col_project_width, table_col_status_width,
|
||||||
|
DATE_FORMAT, TABLE_FILTER_BAR_INITIAL_HEIGHT, TABLE_MAX_DESCRIPTION_LENGTH,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
@@ -183,7 +187,7 @@ impl TaskRow {
|
|||||||
if is_today {
|
if is_today {
|
||||||
"Today".to_string()
|
"Today".to_string()
|
||||||
} else {
|
} else {
|
||||||
dt.format("%d-%m-%Y").to_string()
|
dt.format(DATE_FORMAT).to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -201,7 +205,7 @@ impl From<&task::Task> for TaskRow {
|
|||||||
Self {
|
Self {
|
||||||
uuid: value.uuid,
|
uuid: value.uuid,
|
||||||
id_display: value.working_id.unwrap_or(0).to_string(),
|
id_display: value.working_id.unwrap_or(0).to_string(),
|
||||||
description: Self::truncate(&value.description, 50),
|
description: Self::truncate(&value.description, TABLE_MAX_DESCRIPTION_LENGTH),
|
||||||
project: value.project.clone().unwrap_or(String::new()),
|
project: value.project.clone().unwrap_or(String::new()),
|
||||||
due: Self::format_date(&value.due, value.is_due_today()),
|
due: Self::format_date(&value.due, value.is_due_today()),
|
||||||
priority: value.priority.into(),
|
priority: value.priority.into(),
|
||||||
@@ -320,7 +324,7 @@ impl TaskTable {
|
|||||||
selected_page_idx: None,
|
selected_page_idx: None,
|
||||||
selected_global_idx: None,
|
selected_global_idx: None,
|
||||||
need_reload: true,
|
need_reload: true,
|
||||||
filter_bar_height: gpui::px(52.0),
|
filter_bar_height: TABLE_FILTER_BAR_INITIAL_HEIGHT,
|
||||||
search_input,
|
search_input,
|
||||||
status_dropdown,
|
status_dropdown,
|
||||||
priority_dropdown,
|
priority_dropdown,
|
||||||
@@ -515,7 +519,7 @@ impl TaskTable {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let label = Self::format_due_label(date);
|
let label = Self::format_due_label(date);
|
||||||
let value = format!("date:{}", date.format("%Y-%m-%d"));
|
let value = format!("date:{}", date.format(DATE_FORMAT));
|
||||||
items.push(DropdownItem::with_value(label, value));
|
items.push(DropdownItem::with_value(label, value));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -538,7 +542,7 @@ impl TaskTable {
|
|||||||
if date == today {
|
if date == today {
|
||||||
"Today".to_string()
|
"Today".to_string()
|
||||||
} else {
|
} else {
|
||||||
date.format("%d-%m-%Y").to_string()
|
date.format(DATE_FORMAT).to_string()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -729,7 +733,7 @@ impl TaskTable {
|
|||||||
.font_weight(gpui::FontWeight::MEDIUM)
|
.font_weight(gpui::FontWeight::MEDIUM)
|
||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.min_w(gpui::rems(3.0))
|
.min_w(table_col_id_width())
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
@@ -739,22 +743,22 @@ impl TaskTable {
|
|||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.min_w(gpui::rems(10.0))
|
.min_w(table_col_desc_min_width())
|
||||||
.child(self.render_header_column(SortColumn::Description, "header-desc", cx)),
|
.child(self.render_header_column(SortColumn::Description, "header-desc", cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.w(gpui::rems(10.0))
|
.w(table_col_project_width())
|
||||||
.child(self.render_header_column(SortColumn::Project, "header-project", cx)),
|
.child(self.render_header_column(SortColumn::Project, "header-project", cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.w(gpui::rems(7.0))
|
.w(table_col_due_width())
|
||||||
.child(self.render_header_column(SortColumn::Due, "header-due", cx)),
|
.child(self.render_header_column(SortColumn::Due, "header-due", cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.w(gpui::rems(5.0))
|
.w(table_col_priority_width())
|
||||||
.child(self.render_header_column(SortColumn::Priority, "header-priority", cx)),
|
.child(self.render_header_column(SortColumn::Priority, "header-priority", cx)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
@@ -788,7 +792,7 @@ impl TaskTable {
|
|||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.min_w(gpui::rems(3.0))
|
.min_w(table_col_id_width())
|
||||||
.flex()
|
.flex()
|
||||||
.items_center()
|
.items_center()
|
||||||
.gap_1()
|
.gap_1()
|
||||||
@@ -801,7 +805,7 @@ impl TaskTable {
|
|||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.flex_1()
|
.flex_1()
|
||||||
.min_w(gpui::rems(10.0))
|
.min_w(table_col_desc_min_width())
|
||||||
.overflow_x_hidden()
|
.overflow_x_hidden()
|
||||||
.child(
|
.child(
|
||||||
components::label::Label::new(row.description.clone())
|
components::label::Label::new(row.description.clone())
|
||||||
@@ -822,11 +826,11 @@ impl TaskTable {
|
|||||||
))
|
))
|
||||||
.child(
|
.child(
|
||||||
gpui::div()
|
gpui::div()
|
||||||
.w(gpui::rems(5.0))
|
.w(table_col_priority_width())
|
||||||
.child(priority_badge(&row.priority, theme)),
|
.child(priority_badge(&row.priority, theme)),
|
||||||
)
|
)
|
||||||
.child(
|
.child(
|
||||||
gpui::div().w(gpui::rems(6.0)).child(
|
gpui::div().w(table_col_status_width()).child(
|
||||||
components::label::Label::new(row.status.clone())
|
components::label::Label::new(row.status.clone())
|
||||||
.text_color(self.status_color(row, cx)),
|
.text_color(self.status_color(row, cx)),
|
||||||
),
|
),
|
||||||
|
|||||||
Reference in New Issue
Block a user