pretty good

This commit is contained in:
2025-07-28 08:14:15 -04:00
parent 36a576dc2c
commit 4dd632012f
21 changed files with 2174 additions and 152 deletions

View File

@@ -69,9 +69,11 @@ class FlowAnalysisWidget(Vertical):
if not self.flow_table:
return
# Preserve cursor position
# Preserve cursor and scroll positions
cursor_row = self.flow_table.cursor_row
cursor_column = self.flow_table.cursor_column
scroll_x = self.flow_table.scroll_x
scroll_y = self.flow_table.scroll_y
selected_row_key = None
if self.flow_table.rows and cursor_row < len(self.flow_table.rows):
selected_row_key = list(self.flow_table.rows.keys())[cursor_row]
@@ -108,6 +110,9 @@ class FlowAnalysisWidget(Vertical):
# If original selection not found, try to maintain row position
new_row = min(cursor_row, self.flow_table.row_count - 1)
self.flow_table.move_cursor(row=new_row, column=cursor_column, animate=False)
# Restore scroll position
self.flow_table.scroll_to(x=scroll_x, y=scroll_y, animate=False)
def _create_flow_row(self, flow_num: int, flow: 'FlowStats') -> List[Text]:
"""Create main flow row with rich text formatting"""

View File

@@ -29,11 +29,15 @@ class EnhancedFlowTable(Vertical):
DEFAULT_CSS = """
EnhancedFlowTable {
height: 1fr;
padding: 0;
margin: 0;
}
EnhancedFlowTable DataTable {
height: 1fr;
scrollbar-gutter: stable;
padding: 0;
margin: 0;
}
"""
@@ -62,17 +66,15 @@ class EnhancedFlowTable(Vertical):
"""Initialize the table"""
table = self.query_one("#flows-data-table", DataTable)
# Add columns with explicit keys to avoid auto-generated keys
table.add_column("#", width=3, key="num")
table.add_column("Source", width=22, key="source")
table.add_column("Proto", width=6, key="proto")
table.add_column("Destination", width=22, key="dest")
table.add_column("Extended", width=10, key="extended")
table.add_column("Frame Type", width=12, key="frame_type")
table.add_column("Rate", width=12, key="rate")
table.add_column("Volume", width=12, key="volume")
table.add_column("Quality", width=12, key="quality")
table.add_column("Status", width=8, key="status")
# Compact columns optimized for data density
table.add_column("#", width=2, key="num")
table.add_column("Source", width=18, key="source")
table.add_column("Proto", width=4, key="proto")
table.add_column("Destination", width=18, key="dest")
table.add_column("Extended", width=8, key="extended")
table.add_column("Frame Type", width=10, key="frame_type")
table.add_column("Pkts", width=6, key="rate")
table.add_column("Size", width=8, key="volume")
self.refresh_data()
@@ -80,9 +82,11 @@ class EnhancedFlowTable(Vertical):
"""Refresh flow table with enhanced visualizations"""
table = self.query_one("#flows-data-table", DataTable)
# Preserve cursor position
# Preserve cursor and scroll positions
cursor_row = table.cursor_row
cursor_column = table.cursor_column
scroll_x = table.scroll_x
scroll_y = table.scroll_y
selected_row_key = None
if table.rows and cursor_row < len(table.rows):
selected_row_key = list(table.rows.keys())[cursor_row]
@@ -148,6 +152,9 @@ class EnhancedFlowTable(Vertical):
# If original selection not found, try to maintain row position
new_row = min(cursor_row, table.row_count - 1)
table.move_cursor(row=new_row, column=cursor_column, animate=False)
# Restore scroll position
table.scroll_to(x=scroll_x, y=scroll_y, animate=False)
def _create_enhanced_row(self, num: int, flow: 'FlowStats', metrics: dict) -> List[Text]:
"""Create enhanced row with inline visualizations"""
@@ -177,10 +184,9 @@ class EnhancedFlowTable(Vertical):
rate_spark = self._create_rate_sparkline(metrics['rate_history'])
rate_text = Text(f"{metrics['rate_history'][-1]:.0f} {rate_spark}")
# Volume with bar chart
volume_bar = self._create_volume_bar(flow.total_bytes)
volume_value = self._format_bytes(flow.total_bytes)
volume_text = Text(f"{volume_value:>6} {volume_bar}")
# Size with actual value
size_value = self._format_bytes(flow.total_bytes)
size_text = Text(f"{size_value:>8}")
# Quality with bar chart and color
quality_bar, quality_color = self._create_quality_bar(flow)
@@ -199,8 +205,7 @@ class EnhancedFlowTable(Vertical):
return [
num_text, source_text, proto_text, dest_text,
extended_text, frame_text, rate_text, volume_text,
quality_text, status_text
extended_text, frame_text, rate_text, size_text
]
def _create_rate_sparkline(self, history: List[float]) -> str:
@@ -308,12 +313,10 @@ class EnhancedFlowTable(Vertical):
Text(""), # Empty source
Text(""), # Empty protocol
Text(""), # Empty destination
Text(f" └─ {extended_proto}", style="dim yellow"),
Text(f" {extended_proto}", style="dim yellow"),
Text(frame_type, style="dim blue"),
Text(f"{count}", style="dim", justify="right"),
Text(f"{percentage:.0f}%", style="dim"),
Text(""), # Empty quality
Text("") # Empty status
Text(f"{self._format_bytes(count * (flow.total_bytes // flow.frame_count) if flow.frame_count > 0 else 0):>8}", style="dim")
]
subrows.append(subrow)

View File

@@ -29,19 +29,23 @@ class MetricCard(Widget):
MetricCard {
width: 1fr;
height: 3;
margin: 0 1;
margin: 0;
padding: 0;
}
MetricCard.success {
border: solid $success;
border: none;
color: #00ff88;
}
MetricCard.warning {
border: solid $warning;
border: none;
color: #ffcc00;
}
MetricCard.error {
border: solid $error;
border: none;
color: #ff3366;
}
"""
@@ -106,18 +110,15 @@ class MetricCard(Widget):
if self.sparkline and self.spark_data:
spark_str = " " + self._create_mini_spark()
# Format content
# Ultra compact - single line format
content = Text()
content.append(f"{self.title}\n", style="dim")
content.append(f"{self.title}: ", style="dim")
content.append(f"{self.value}", style=f"bold {style}")
content.append(trend_icon, style=style)
content.append(spark_str, style="dim cyan")
return Panel(
content,
height=3,
border_style=style if self.color != "normal" else "dim"
)
# Super compact - no panel, just text
return content
def _create_mini_spark(self) -> str:
"""Create mini sparkline for inline display"""