pretty good
This commit is contained in:
@@ -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"""
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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"""
|
||||
|
||||
Reference in New Issue
Block a user