(title: string, events: StoredReportEvent[])
| 215 | } |
| 216 | |
| 217 | function renderHtml(title: string, events: StoredReportEvent[]): string { |
| 218 | const cases = renderCases(groupByCase(events)); |
| 219 | return `<!doctype html> |
| 220 | <html lang="en"> |
| 221 | <head> |
| 222 | <meta charset="utf-8"> |
| 223 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 224 | <title>${escapeHtml(title)}</title> |
| 225 | <style> |
| 226 | :root { color-scheme: light; font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; } |
| 227 | * { box-sizing: border-box; } |
| 228 | html, body { height: 100%; } |
| 229 | body { margin: 0; background: #f4f6f8; color: #151922; overflow: hidden; } |
| 230 | .app { display: grid; grid-template-columns: 260px minmax(0, 1fr); height: 100vh; min-height: 0; } |
| 231 | .case-nav { background: #ffffff; border-right: 1px solid #d9dee7; display: flex; flex-direction: column; min-height: 0; } |
| 232 | .nav-header { padding: 20px 18px 14px; border-bottom: 1px solid #e6eaf0; } |
| 233 | h1 { margin: 0 0 8px; font-size: 20px; line-height: 1.2; } |
| 234 | .summary { color: #596273; font-size: 13px; line-height: 1.45; } |
| 235 | .case-list { padding: 10px; overflow: auto; } |
| 236 | .case-link { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 8px; align-items: center; padding: 7px 9px; border-radius: 0; color: #2d3543; text-decoration: none; border: 1px solid transparent; } |
| 237 | .case-link:hover { background: #f4f7fa; } |
| 238 | .case-link.active { background: #e9f4ef; border-color: #b8d9c9; color: #165f3a; } |
| 239 | .case-name { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; } |
| 240 | .case-count { color: #6d7685; font: 12px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; } |
| 241 | .report { display: grid; grid-template-columns: minmax(680px, 1fr) minmax(320px, 34vw); min-width: 0; min-height: 0; } |
| 242 | .timeline-pane, .detail-pane { min-width: 0; min-height: 0; background: #ffffff; } |
| 243 | .timeline-pane { display: grid; grid-template-rows: auto 1fr; border-right: 1px solid #d9dee7; } |
| 244 | .detail-pane { display: grid; grid-template-rows: auto 1fr; } |
| 245 | .lane-head { display: grid; grid-template-columns: 38px minmax(0, 1fr) 22px minmax(0, 1fr); gap: 0; align-items: center; height: 34px; padding: 0 10px; border-bottom: 1px solid #e6eaf0; background: #fbfcfd; color: #5a6371; font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em; } |
| 246 | .lane-head-spine { height: 100%; border-left: 1px solid #d7dde5; justify-self: center; } |
| 247 | .event-scroll, .detail-scroll { overflow: auto; min-height: 0; scroll-behavior: smooth; } |
| 248 | .case-section { padding: 10px 10px 4px; } |
| 249 | .case-section + .case-section { border-top: 1px solid #eef1f5; } |
| 250 | .case-title { margin: 0 0 7px; font-size: 14px; line-height: 1.25; color: #202633; } |
| 251 | .swimlanes { list-style: none; margin: 0; padding: 0; } |
| 252 | .swim-row { display: grid; grid-template-columns: 38px minmax(0, 1fr) 22px minmax(0, 1fr); align-items: start; min-height: 30px; } |
| 253 | .swim-row.lifecycle { min-height: 30px; } |
| 254 | .time { padding-top: 5px; color: #707a89; font: 11px ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; } |
| 255 | .spine { position: relative; min-height: 30px; } |
| 256 | .spine::before { content: ""; position: absolute; top: 0; bottom: 0; left: 50%; border-left: 1px solid #d7dde5; } |
| 257 | .dot { position: absolute; top: 8px; left: calc(50% - 4px); width: 8px; height: 8px; border-radius: 999px; background: #8792a2; box-shadow: 0 0 0 3px #ffffff; } |
| 258 | .swim-row.active .dot { background: #0d7f4f; box-shadow: 0 0 0 3px #dff2e9; } |
| 259 | .lane { padding: 2px 0 3px; min-width: 0; } |
| 260 | .lane-left { padding-right: 6px; } |
| 261 | .lane-right { padding-left: 6px; } |
| 262 | .event-card { width: 100%; min-height: 26px; border: 1px solid #dfe5ec; border-radius: 0; background: #ffffff; color: #1f2633; display: flex; align-items: center; padding: 3px 7px; text-align: left; cursor: pointer; font: inherit; } |
| 263 | .event-card:hover { border-color: #b8c4d2; background: #fbfcfd; } |
| 264 | .swim-row.active .event-card { border-color: #2f9f68; background: #f4fbf7; } |
| 265 | .event-card.http { border-left: 2px solid #1f8f55; } |
| 266 | .event-card.ws { border-left: 2px solid #b56b00; } |
| 267 | .event-card.log { border-left: 2px solid #607086; } |
| 268 | .event-card.test-result { border-left: 2px solid #6c4acb; } |
| 269 | .event-card.life-event { grid-column: 2 / 5; grid-row: 1; justify-self: center; align-self: start; width: min(320px, 60%); margin-top: 2px; z-index: 1; border-left: 2px solid #8792a2; } |
| 270 | .event-title { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; font-weight: 700; line-height: 1.25; } |
| 271 | .detail-head { height: 34px; padding: 9px 12px 0; border-bottom: 1px solid #e6eaf0; background: #fbfcfd; font-size: 13px; font-weight: 700; color: #303746; } |
| 272 | .detail-case { padding: 10px 12px 0; } |
| 273 | .detail-case-title { margin: 0 0 8px; font-size: 13px; color: #202633; } |
| 274 | .detail-card { border: 1px solid #dfe5ec; border-radius: 0; margin: 0 0 8px; background: #ffffff; overflow: hidden; } |
no test coverage detected