Class: Bidi2pdf::Bidi::NetworkEventFormatters::NetworkEventHtmlFormatter

Inherits:
Object
  • Object
show all
Includes:
NetworkEventFormatterUtils
Defined in:
lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb

Instance Method Summary collapse

Methods included from NetworkEventFormatterUtils

#format_bytes, #format_timestamp, #parse_timing, #shorten_url

Instance Method Details

#render(events) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
# File 'lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb', line 9

def render(events)
  return unless Bidi2pdf.network_events_logger.info?

  "    <!DOCTYPE html>\n    <html lang=\"en\" data-bs-theme=\"light\">\n    <head>\n      <meta charset=\"UTF-8\">\n      <title>Network Events</title>\n      <link href=\"https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css\" rel=\"stylesheet\">\n      <style>\n        body { font-family: monospace; padding: 2rem; }\n        .event { background: var(--bs-body-bg); border: 1px solid var(--bs-border-color); padding: 1rem; margin-bottom: 2rem; border-radius: .5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n        .bar-container { position: relative; height: 20px; background: var(--bs-secondary-bg); border-radius: 4px; }\n        .bar { position: absolute; top: 0; height: 100%; background-color: #0d6efd; opacity: 0.8; }\n        .toc a { text-decoration: none; display: block; margin-bottom: 0.5rem; }\n\n        @media print {\n          .no-break {\n            page-break-inside: avoid;\n          }\n    \#{\"    \"}\n    \#{\"     \"}\n          .form-select, .form-label, #theme-select {\n            display: none !important; /* Hide theme selector when printing */\n          }\n        }\n\n        .event {\n          word-break: break-word;\n          overflow-wrap: anywhere;\n        }\n      </style>\n      <script>\n        function toggleTheme(value) {\n          document.documentElement.setAttribute('data-bs-theme', value);\n        }\n      </script>\n    </head>\n    <body>\n      <h1>Network Events</h1>\n      <div class=\"mb-4\">\n        <label for=\"theme-select\" class=\"form-label\">Theme:</label>\n        <select id=\"theme-select\" class=\"form-select w-auto d-inline-block\" onchange=\"toggleTheme(this.value)\">\n          <option value=\"light\">Light</option>\n          <option value=\"dark\">Dark</option>\n        </select>\n      </div>\n\n      <h2>Index</h2>\n      <div class=\"toc mb-4\">\n        \#{events.map.with_index { |e, i| toc_entry(e, i) }.join(\"\\n\")}\n      </div>\n\n      \#{events.map.with_index { |e, i| render_event(e, i) }.join(\"\\n\")}\n    </body>\n    </html>\n  HTML\nend\n"

#render_event(event, index) ⇒ Object

rubocop: disable Metrics/AbcSize



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
# File 'lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb', line 74

def render_event(event, index)
  timing = parse_timing(event)
  duration = event.duration_seconds || 0
  duration_str = event.in_progress? ? "in progress" : "#{duration}s"
  status = event.http_status_code || "?"
  method = event.http_method || "?"
  start = format_timestamp(event.start_timestamp)
  finish = event.end_timestamp ? format_timestamp(event.end_timestamp) : "..."
  bytes = event.bytes_received ? format_bytes(event.bytes_received) : "N/A"
  bars = render_timing_bars(timing)
  displayed_url = shorten_url(event.url)

  "    <div class=\"event no-break\" id=\"event-\#{index}\">\n      <div><strong>Request:</strong> \#{method} \#{displayed_url}</div>\n      <div><strong>Status:</strong> HTTP \#{status}</div>\n      <div><strong>State:</strong> \#{event.state}</div>\n      <div><strong>Start:</strong> \#{start}</div>\n      <div><strong>End:</strong> \#{finish}</div>\n      <div><strong>Duration:</strong> \#{duration_str}</div>\n      <div><strong>Received:</strong> \#{bytes}</div>\n      \#{bars}\n    </div>\n  HTML\nend\n"

#render_timing_bars(timing) ⇒ Object

rubocop: enable Metrics/AbcSize



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb', line 102

def render_timing_bars(timing)
  return "" if timing.empty?

  max_ms = timing.map { |t| t[:ms] }.max
  scale = max_ms.zero? ? 0 : 100.0 / max_ms

  bars = timing.map do |t|
    width = (t[:ms] * scale).clamp(1, 100).round(2)
    "      <div>\n        <small>\#{t[:label]} (\#{t[:ms]} ms)</small>\n        <div class=\"bar-container mb-2\">\n          <div class=\"bar\" style=\"width: \#{width}%\"></div>\n        </div>\n      </div>\n    HTML\n  end\n\n  \"<div class=\\\"mt-3\\\"><strong>Timing Waterfall</strong>\#{bars.join}</div>\"\nend\n"

#toc_entry(event, index) ⇒ Object



69
70
71
# File 'lib/bidi2pdf/bidi/network_event_formatters/network_event_html_formatter.rb', line 69

def toc_entry(event, index)
  "<a href=\"#event-#{index}\">[#{index + 1}] #{event.http_method} #{event.url}</a>"
end