style: Restore titles and apply full-height rounded borders to Call Detail view
This commit is contained in:
@@ -857,60 +857,89 @@ func (m Model) renderCallDetail() string {
|
||||
// Split Widths and Heights
|
||||
totalWidth := m.width
|
||||
// Subtract borders/padding if any
|
||||
innerW := totalWidth - 4
|
||||
innerW := totalWidth - 2 // Outer margin?
|
||||
leftW := innerW / 2
|
||||
rightW := innerW - leftW
|
||||
|
||||
// Left Pane Heights
|
||||
leftTotalH := m.height - 3 // Nav + Status
|
||||
leftTopH := leftTotalH / 3 // 1/3 for call summary
|
||||
leftBotH := leftTotalH - leftTopH // 2/3 for packet details
|
||||
// Adjust for borders: we have two boxes stacked.
|
||||
// Let's say we split space 33% / 66%.
|
||||
leftTopH := leftTotalH / 3
|
||||
leftBotH := leftTotalH - leftTopH
|
||||
|
||||
if leftTopH < 10 {
|
||||
leftTopH = 10
|
||||
} // Min height
|
||||
if leftBotH < 0 {
|
||||
leftBotH = 0
|
||||
}
|
||||
|
||||
// Determine Border Colors based on Focus
|
||||
detailsBorderColor := lipgloss.Color("#44475A")
|
||||
flowBorderColor := lipgloss.Color("#44475A")
|
||||
infoBorderColor := lipgloss.Color("#44475A") // Call info usually static focus
|
||||
|
||||
if m.focusPacketDetails {
|
||||
detailsBorderColor = lipgloss.Color("#bd93f9") // Active Purple
|
||||
} else {
|
||||
flowBorderColor = lipgloss.Color("#bd93f9")
|
||||
}
|
||||
|
||||
// Definition of Styles
|
||||
// We want Borders on ALL sides now since they are distinct boxes
|
||||
baseStyle := lipgloss.NewStyle().Padding(0, 1).Border(lipgloss.RoundedBorder())
|
||||
|
||||
leftTopStyle := baseStyle.Copy().
|
||||
Width(leftW - 2). // -2 for borders
|
||||
Height(leftTopH - 2). // -2 for borders
|
||||
BorderForeground(infoBorderColor)
|
||||
|
||||
leftBotStyle := baseStyle.Copy().
|
||||
Width(leftW - 2).
|
||||
Height(leftBotH - 2).
|
||||
BorderForeground(detailsBorderColor)
|
||||
|
||||
rightStyle := baseStyle.Copy().
|
||||
Width(rightW - 2).
|
||||
Height(leftTotalH - 2).
|
||||
BorderForeground(flowBorderColor)
|
||||
|
||||
// --- Left Pane TOP (Call Info) ---
|
||||
var leftTop strings.Builder
|
||||
// Title
|
||||
leftTop.WriteString(m.styles.Title.Render("📞 Call Detail"))
|
||||
leftTop.WriteString("\n\n")
|
||||
|
||||
// Content
|
||||
leftTop.WriteString(fmt.Sprintf("Call-ID: %s\n", flow.CallID))
|
||||
leftTop.WriteString(fmt.Sprintf("From: %s\n", flow.From))
|
||||
leftTop.WriteString(fmt.Sprintf("To: %s\n", flow.To))
|
||||
leftTop.WriteString(fmt.Sprintf("State: %s\n", flow.State))
|
||||
|
||||
// Calculate and display duration
|
||||
duration := flow.EndTime.Sub(flow.StartTime)
|
||||
leftTop.WriteString(fmt.Sprintf("Duration: %s\n", duration.Round(time.Millisecond)))
|
||||
|
||||
leftTop.WriteString(fmt.Sprintf("Packets: %d\n\n", len(flow.Packets)))
|
||||
|
||||
// Network Summary Section
|
||||
leftTop.WriteString("Network Layer:\n")
|
||||
// Find first packet to get initial IPs
|
||||
if len(flow.Packets) > 0 {
|
||||
first := flow.Packets[0]
|
||||
|
||||
srcLabel := m.networkMap.LabelForIP(first.SourceIP)
|
||||
if srcLabel != first.SourceIP {
|
||||
// Find node type to apply style
|
||||
node := m.networkMap.FindByIP(first.SourceIP)
|
||||
srcLabel = m.styleForNode(node).Render(srcLabel)
|
||||
}
|
||||
|
||||
dstLabel := m.networkMap.LabelForIP(first.DestIP)
|
||||
if dstLabel != first.DestIP {
|
||||
node := m.networkMap.FindByIP(first.DestIP)
|
||||
dstLabel = m.styleForNode(node).Render(dstLabel)
|
||||
}
|
||||
|
||||
leftTop.WriteString(fmt.Sprintf(" Source: %s (%s:%d)\n", srcLabel, first.SourceIP, first.SourcePort))
|
||||
leftTop.WriteString(fmt.Sprintf(" Destination: %s (%s:%d)\n", dstLabel, first.DestIP, first.DestPort))
|
||||
}
|
||||
|
||||
// --- Left Pane BOTTOM (Selected Packet Details) ---
|
||||
// Title
|
||||
detailsTitle := m.styles.Title.Render("📦 Packet Details")
|
||||
|
||||
// Content
|
||||
var detailsContent string
|
||||
if m.selectedPacketIndex < len(flow.Packets) {
|
||||
pkt := flow.Packets[m.selectedPacketIndex]
|
||||
@@ -922,26 +951,35 @@ func (m Model) renderCallDetail() string {
|
||||
detailsContent = "No packet selected"
|
||||
}
|
||||
|
||||
// Update details viewport content
|
||||
// Update details viewport
|
||||
// Calculate available height: Pane Height - Borders(2) - Header(2 approx)
|
||||
// Actually styles handle borders on the container.
|
||||
// Viewport height should be container InnerHeight - TitleHeight - Padding.
|
||||
// leftBotStyle.GetHeight() returns outer height.
|
||||
// We set style height explicitly, so we know it.
|
||||
|
||||
vpHeight := (leftBotH - 2) - 2 // -2 Borders, -2 Title/Margin
|
||||
if vpHeight < 0 {
|
||||
vpHeight = 0
|
||||
}
|
||||
|
||||
m.detailsViewport.Width = leftW - 4 // Margin/Padding
|
||||
m.detailsViewport.Height = vpHeight
|
||||
m.detailsViewport.SetContent(detailsContent)
|
||||
m.detailsViewport.Width = leftW - 2 // Account for padding/borders roughly
|
||||
m.detailsViewport.Height = leftBotH
|
||||
|
||||
// --- Right Pane (Transaction Flow) ---
|
||||
var right strings.Builder
|
||||
// right.WriteString("Transaction Flow:\n\n") // Removed header to save space or added to viewport content
|
||||
// Title
|
||||
flowTitle := m.styles.Title.Render("🚀 Transaction Flow")
|
||||
|
||||
var right strings.Builder
|
||||
for i, pkt := range flow.Packets {
|
||||
arrow := "→"
|
||||
arrowStyle := m.styles.ArrowOut
|
||||
|
||||
// Simple direction indicator based on whether it matches initial source
|
||||
if len(flow.Packets) > 0 && pkt.SourceIP != flow.Packets[0].SourceIP {
|
||||
arrow = "←"
|
||||
arrowStyle = m.styles.ArrowIn
|
||||
}
|
||||
|
||||
// Style the packet summary (Method or Status)
|
||||
var summaryStyle lipgloss.Style
|
||||
if pkt.IsRequest {
|
||||
switch pkt.Method {
|
||||
@@ -971,17 +1009,9 @@ func (m Model) renderCallDetail() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Format timestamp
|
||||
ts := pkt.Timestamp.Format("15:04:05.000")
|
||||
lineStr := fmt.Sprintf("%d. [%s] %s %s", i+1, ts, arrowStyle.Render(arrow), summaryStyle.Render(pkt.Summary()))
|
||||
|
||||
// Clean packet info line (Timestamp + Arrow + Method/Status)
|
||||
lineStr := fmt.Sprintf("%d. [%s] %s %s",
|
||||
i+1,
|
||||
ts,
|
||||
arrowStyle.Render(arrow),
|
||||
summaryStyle.Render(pkt.Summary()))
|
||||
|
||||
// Show SDP info if present
|
||||
if pkt.SDP != nil {
|
||||
mediaIP := pkt.SDP.GetSDPMediaIP()
|
||||
if mediaIP != "" {
|
||||
@@ -994,44 +1024,39 @@ func (m Model) renderCallDetail() string {
|
||||
}
|
||||
}
|
||||
|
||||
// Highlight selected line
|
||||
if i == m.selectedPacketIndex {
|
||||
lineStr = m.styles.Active.Render("> " + lineStr)
|
||||
} else {
|
||||
lineStr = " " + lineStr
|
||||
}
|
||||
|
||||
right.WriteString(lineStr + "\n")
|
||||
}
|
||||
|
||||
// Set content to viewport
|
||||
m.viewport.SetContent(right.String())
|
||||
|
||||
// Determine Border Colors based on Focus
|
||||
detailsBorderColor := lipgloss.Color("#44475A")
|
||||
flowBorderColor := lipgloss.Color("#44475A")
|
||||
|
||||
if m.focusPacketDetails {
|
||||
detailsBorderColor = lipgloss.Color("#bd93f9") // Active Purple
|
||||
} else {
|
||||
flowBorderColor = lipgloss.Color("#bd93f9")
|
||||
// Right Pane Height logic
|
||||
rvpHeight := (leftTotalH - 2) - 2 // -2 Borders, -2 Title/Margin
|
||||
if rvpHeight < 0 {
|
||||
rvpHeight = 0
|
||||
}
|
||||
m.viewport.Height = rvpHeight
|
||||
m.viewport.Width = rightW - 4
|
||||
|
||||
// Layout Construction
|
||||
leftTopStyle := lipgloss.NewStyle().Width(leftW).Height(leftTopH).Padding(1, 2)
|
||||
leftBotStyle := lipgloss.NewStyle().Width(leftW).Height(leftBotH).Padding(0, 1).Border(lipgloss.NormalBorder(), true, false, false, false).BorderForeground(detailsBorderColor)
|
||||
rightStyle := lipgloss.NewStyle().Width(rightW).Padding(0, 1).Border(lipgloss.NormalBorder(), false, false, false, true).BorderForeground(flowBorderColor)
|
||||
// Render Final Layout
|
||||
|
||||
// Render left pane parts
|
||||
// Left Top: Just content
|
||||
leftTopRendered := leftTopStyle.Render(leftTop.String())
|
||||
// Use detailsViewport view
|
||||
leftBotRendered := leftBotStyle.Render(m.detailsViewport.View())
|
||||
|
||||
// Combine Left
|
||||
// Left Bot: Title + Viewport
|
||||
leftBotContent := lipgloss.JoinVertical(lipgloss.Left, detailsTitle, "\n", m.detailsViewport.View())
|
||||
leftBotRendered := leftBotStyle.Render(leftBotContent)
|
||||
|
||||
// Left Col
|
||||
leftCol := lipgloss.JoinVertical(lipgloss.Left, leftTopRendered, leftBotRendered)
|
||||
|
||||
// Render viewport (Right pane)
|
||||
rightRendered := rightStyle.Render(m.viewport.View())
|
||||
// Right: Title + Viewport
|
||||
rightContent := lipgloss.JoinVertical(lipgloss.Left, flowTitle, "\n", m.viewport.View())
|
||||
rightRendered := rightStyle.Render(rightContent)
|
||||
|
||||
return lipgloss.JoinHorizontal(lipgloss.Top, leftCol, rightRendered)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user