use std::collections::HashSet;
use serde::{Deserialize, Serialize};
use strum::Display;
use crate::state::SidebarSection;
use crate::tui::NotifyBatch;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum ListenerState {
#[default]
Disconnected,
Connecting,
Connected,
Reconnecting,
}
use crate::models::{
ActiveWorkerRow, AggregatedBreakdownRow, ClusterCapacitySummary, ClusterUtilizationPoint,
DeadWorkerRow, FilterValue, OverloadedWorkerAlert, SnapshotAgeBucket, StaleClaimsAlert,
TaskDetail, TaskListRow, TaskStatusRow, WorkerLoadPoint, WorkerQueuesRow, WorkerUptimeRow,
WorkflowRow, WorkflowSummary, WorkflowTaskRow,
};
#[derive(Debug, Clone, Display)]
pub enum Action {
Tick,
Render,
Resize(u16, u16),
Suspend,
Resume,
Quit,
ClearScreen,
Error(String),
ToggleHelp,
NextTheme,
SwitchTab(Tab),
NavigateWorkerUp,
NavigateWorkerDown,
NavigateTaskUp,
NavigateTaskDown,
OpenTaskDetail(String), CloseTaskDetail,
ScrollTaskDetailUp,
ScrollTaskDetailDown,
ScrollTaskDetailPageUp,
ScrollTaskDetailPageDown,
ScrollTaskDetailHome,
ScrollTaskDetailEnd,
SetTaskDetailScroll(u16),
CopyTaskToClipboard,
NavigateTaskDetailNext, NavigateTaskDetailPrev,
ToggleTaskStatusFilter(TaskStatus),
SelectAllTaskStatuses,
ClearTaskStatuses,
ToggleRetriedFilter,
ToggleTaskRow,
EnterTaskListView(Option<String>), ExitTaskListView, NavigateTaskListUp,
NavigateTaskListDown,
RefreshTaskList,
EnterSidebarSection(SidebarSection),
ExitSidebarSection,
SidebarCursorUp,
SidebarCursorDown,
SidebarToggleFilter, NavigateTaskIdUp,
NavigateTaskIdDown,
NavigatePageUp,
NavigatePageDown,
NavigateHome,
NavigateEnd,
CycleTimeWindowForward,
CycleTimeWindowBackward,
RefreshCurrentTab,
RefreshDashboard,
RefreshWorkers,
RefreshTasks,
RefreshMaintenance,
RefreshWorkflows,
NavigateWorkflowUp,
NavigateWorkflowDown,
OpenWorkflowDetail(String), CloseWorkflowDetail,
ScrollWorkflowDetailUp,
ScrollWorkflowDetailDown,
ScrollWorkflowDetailPageUp,
ScrollWorkflowDetailPageDown,
ScrollWorkflowDetailHome,
ScrollWorkflowDetailEnd,
SetWorkflowDetailScroll(u16),
NavigateWorkflowDetailNext, NavigateWorkflowDetailPrev, CopyWorkflowToClipboard,
ToggleWorkflowStatusFilter(WorkflowStatus),
SelectAllWorkflowStatuses,
ClearWorkflowStatuses,
OpenErrorModal, CloseErrorModal, CopyErrorToClipboard, ClearAllErrors,
DataLoaded(DataUpdate),
DataLoadError(String, DataSource),
StartLoading(DataSource),
OpenSearch,
CloseSearch,
SearchInput(char),
SearchBackspace,
SearchClear,
SearchSelectUp,
SearchSelectDown,
SearchSelectPageUp,
SearchSelectPageDown,
SearchSelectHome,
SearchSelectEnd,
SearchSetScroll(usize),
SearchSelectIndex(usize),
SearchConfirm,
NotifyRefresh(NotifyBatch),
ListenerStateChanged(ListenerState),
}
#[derive(Debug, Clone)]
pub enum SearchMatch {
Worker {
worker_id: String,
hostname: String,
status: String,
},
Task {
task_id: String,
worker_id: String,
status: String,
},
Workflow {
workflow_id: String,
name: String,
status: String,
},
ModalLine {
line_number: usize,
content: String,
},
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Display, Serialize, Deserialize)]
pub enum TimeWindow {
FiveMinutes,
ThirtyMinutes,
OneHour,
SixHours,
TwentyFourHours,
}
impl TimeWindow {
pub fn label(&self) -> &'static str {
match self {
TimeWindow::FiveMinutes => "5m",
TimeWindow::ThirtyMinutes => "30m",
TimeWindow::OneHour => "1h",
TimeWindow::SixHours => "6h",
TimeWindow::TwentyFourHours => "24h",
}
}
pub fn interval(&self) -> &'static str {
match self {
TimeWindow::FiveMinutes => "5 minutes",
TimeWindow::ThirtyMinutes => "30 minutes",
TimeWindow::OneHour => "1 hour",
TimeWindow::SixHours => "6 hours",
TimeWindow::TwentyFourHours => "24 hours",
}
}
pub fn next(&self) -> Self {
match self {
TimeWindow::FiveMinutes => TimeWindow::ThirtyMinutes,
TimeWindow::ThirtyMinutes => TimeWindow::OneHour,
TimeWindow::OneHour => TimeWindow::SixHours,
TimeWindow::SixHours => TimeWindow::TwentyFourHours,
TimeWindow::TwentyFourHours => TimeWindow::FiveMinutes,
}
}
pub fn prev(&self) -> Self {
match self {
TimeWindow::FiveMinutes => TimeWindow::TwentyFourHours,
TimeWindow::ThirtyMinutes => TimeWindow::FiveMinutes,
TimeWindow::OneHour => TimeWindow::ThirtyMinutes,
TimeWindow::SixHours => TimeWindow::OneHour,
TimeWindow::TwentyFourHours => TimeWindow::SixHours,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display, Serialize, Deserialize)]
pub enum TaskStatus {
Pending,
Claimed,
Running,
Completed,
Failed,
Cancelled,
Expired,
}
impl TaskStatus {
pub fn all() -> Vec<Self> {
vec![
TaskStatus::Pending,
TaskStatus::Claimed,
TaskStatus::Running,
TaskStatus::Completed,
TaskStatus::Failed,
TaskStatus::Cancelled,
TaskStatus::Expired,
]
}
pub fn label(&self) -> &'static str {
match self {
TaskStatus::Pending => "Pending",
TaskStatus::Claimed => "Claimed",
TaskStatus::Running => "Running",
TaskStatus::Completed => "Completed",
TaskStatus::Failed => "Failed",
TaskStatus::Cancelled => "Cancelled",
TaskStatus::Expired => "Expired",
}
}
pub fn db_value(&self) -> &'static str {
match self {
TaskStatus::Pending => "PENDING",
TaskStatus::Claimed => "CLAIMED",
TaskStatus::Running => "RUNNING",
TaskStatus::Completed => "COMPLETED",
TaskStatus::Failed => "FAILED",
TaskStatus::Cancelled => "CANCELLED",
TaskStatus::Expired => "EXPIRED",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct TaskStatusFilter {
pub selected: HashSet<TaskStatus>,
}
impl Default for TaskStatusFilter {
fn default() -> Self {
let mut selected = HashSet::new();
selected.insert(TaskStatus::Claimed);
selected.insert(TaskStatus::Running);
Self { selected }
}
}
impl TaskStatusFilter {
pub fn toggle(&mut self, status: TaskStatus) {
if self.selected.contains(&status) {
self.selected.remove(&status);
} else {
self.selected.insert(status);
}
}
pub fn is_selected(&self, status: &TaskStatus) -> bool {
self.selected.contains(status)
}
pub fn select_all(&mut self) {
self.selected = TaskStatus::all().into_iter().collect();
}
pub fn clear(&mut self) {
self.selected.clear();
}
pub fn to_sql_values(&self) -> Vec<&'static str> {
self.selected.iter().map(|s| s.db_value()).collect()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display, Serialize, Deserialize)]
pub enum WorkflowStatus {
Pending,
Running,
Completed,
Failed,
Paused,
Cancelled,
}
impl WorkflowStatus {
pub fn all() -> Vec<Self> {
vec![
WorkflowStatus::Pending,
WorkflowStatus::Running,
WorkflowStatus::Completed,
WorkflowStatus::Failed,
WorkflowStatus::Paused,
WorkflowStatus::Cancelled,
]
}
pub fn label(&self) -> &'static str {
match self {
WorkflowStatus::Pending => "Pending",
WorkflowStatus::Running => "Running",
WorkflowStatus::Completed => "Completed",
WorkflowStatus::Failed => "Failed",
WorkflowStatus::Paused => "Paused",
WorkflowStatus::Cancelled => "Cancelled",
}
}
pub fn db_value(&self) -> &'static str {
match self {
WorkflowStatus::Pending => "PENDING",
WorkflowStatus::Running => "RUNNING",
WorkflowStatus::Completed => "COMPLETED",
WorkflowStatus::Failed => "FAILED",
WorkflowStatus::Paused => "PAUSED",
WorkflowStatus::Cancelled => "CANCELLED",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct WorkflowStatusFilter {
pub selected: HashSet<WorkflowStatus>,
}
impl Default for WorkflowStatusFilter {
fn default() -> Self {
let mut selected = HashSet::new();
selected.insert(WorkflowStatus::Pending);
selected.insert(WorkflowStatus::Running);
selected.insert(WorkflowStatus::Paused);
Self { selected }
}
}
impl WorkflowStatusFilter {
pub fn toggle(&mut self, status: WorkflowStatus) {
if self.selected.contains(&status) {
self.selected.remove(&status);
} else {
self.selected.insert(status);
}
}
pub fn is_selected(&self, status: &WorkflowStatus) -> bool {
self.selected.contains(status)
}
pub fn select_all(&mut self) {
self.selected = WorkflowStatus::all().into_iter().collect();
}
pub fn clear(&mut self) {
self.selected.clear();
}
pub fn to_sql_values(&self) -> Vec<&'static str> {
self.selected.iter().map(|s| s.db_value()).collect()
}
}
#[derive(Debug, Clone, PartialEq, Eq, Display, Serialize, Deserialize)]
pub enum Tab {
Dashboard,
Workers,
Tasks,
Workflows,
Maintenance,
}
#[derive(Debug, Clone)]
pub enum DataUpdate {
ClusterSummary(ClusterCapacitySummary),
TaskStatusView(Vec<TaskStatusRow>),
UtilizationTrend(Vec<ClusterUtilizationPoint>),
Alerts(Vec<OverloadedWorkerAlert>, Vec<StaleClaimsAlert>),
WorkerList(Vec<ActiveWorkerRow>),
WorkerDetails(String, WorkerUptimeRow, WorkerQueuesRow),
WorkerLoad(Vec<WorkerLoadPoint>),
TaskAggregation(Vec<AggregatedBreakdownRow>),
SnapshotAge(Vec<SnapshotAgeBucket>),
DeadWorkers(Vec<DeadWorkerRow>),
TaskDetailLoaded(TaskDetail),
TaskListLoaded(Vec<TaskListRow>),
DistinctFilterValues(Vec<FilterValue>, Vec<FilterValue>, Vec<FilterValue>),
WorkflowSummary(WorkflowSummary),
WorkflowList(Vec<WorkflowRow>),
WorkflowDetailLoaded(WorkflowRow, Vec<WorkflowTaskRow>),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Display, Serialize, Deserialize)]
pub enum DataSource {
ClusterSummary,
TaskStatus,
UtilizationTrend,
Alerts,
WorkerList,
WorkerDetails,
TaskAggregation,
SnapshotAge,
DeadWorkers,
TaskDetailData,
TaskListData,
WorkflowSummary,
WorkflowList,
WorkflowDetail,
}