5a3be3af33b76d69d1fc98ee76b9a37f96e96fc7 max Wed Aug 26 00:36:52 2026 -0700 Add opt-in per-phase request timing to the new hgBlat and hgSession pages, shown in a dialog with &measureTiming=1. refs #38157 New reusable perfTimer collector (lib/perfTimer.c) records labeled wall-clock intervals via clock1000() and emits them as JSON; hgBlat and hgSession attach a timing array to their payload when the existing measureTiming cart/CGI var is set. A shared gbShowTimingDialog helper in utils.js renders the server phases plus a client render-time row in a house-style modal, which opens automatically when measureTiming is on. Confirms the position band/locus annotation loop dominates hgSession, and run-BLAT plus locus lookups dominate hgBlat. diff --git src/hg/htdocs/style/gbModern.css src/hg/htdocs/style/gbModern.css index 163b24f5fe0..f11b1dcb5d7 100644 --- src/hg/htdocs/style/gbModern.css +++ src/hg/htdocs/style/gbModern.css @@ -1,121 +1,134 @@ /* gbModern.css - shared UCSC "modern tool" components in the house style. * * The generic, non-tool-specific pieces of the hgBlat facelift (#37996), promoted here so other * client-rendered CGI pages (hgSession, ...) can reuse them by class name instead of copying rules. * UCSC house style (per the project UI Style Guide): deep-navy nav, tan/wheat title band, steel-blue * section bars, plain Helvetica/Arial, navy links with maroon hover, square corners everywhere. * * Load with webIncludeResourceFile("gbModern.css"). Put the design tokens on a wrapper element by * giving it class "gbApp"; the components below read those tokens via var(). Keep any modal markup * as a DOM descendant of the .gbApp wrapper so the custom properties inherit into it. * * Tool-specific layout (column widths, bespoke widgets) stays in the tool's own stylesheet * (hgBlat.css, hgSession.css); this file is only the shared vocabulary. */ /* Plain white page, matching the track-settings model (gb.css). The framework body is cream * (#FFF9D2) and the hgInside content table carries a BGCOLOR=#FFFEE8 attribute; override both to * white so the tool sits on one uniform background. */ body.cgi { background:#fff; } table.hgInside { background:#fff; } /* Design tokens - the house palette in one place. Applied to a wrapper with class "gbApp". */ .gbApp { --accent:#003a72; --accentHover:#8b1a1a; --navy:#0a2b6b; --ink:#1e2833; --muted:#5b6572; --faint:#93a0ad; --line:#d0d0d0; --lineSoft:#ececec; --card:#ffffff; --panel:#ffffff; --section:#4c759c; --headrow:#ededed; --headrowLine:#cccccc; --sel:#cfe0f5; --hover:#f0f0f0; --stripe:#f7f7f7; --title:#eaca92; --titleLine:#d9bd82; --titleSub:#5a4a24; --btn:#ffffff; --btnLine:#999999; --btnText:#003a72; --btnHover:#eef2f7; --btnDark:#0a2b6b; --btnDarkHover:#0a2350; font-family:'Helvetica Neue',Helvetica,Arial,sans-serif; color:var(--ink); font-size:14px; } /* Main page header, styled like gb.css .gbTrackTitleBanner: black title on the house gold. The * framework's #sectTtl holds the section title emitted by webNewSection/cartWebStart. */ .subheadingBar { background:#eaca92; padding:9px 16px; margin:0; border:0; box-sizing:border-box; } .subheadingBar #sectTtl { color:#000; font-weight:700; font-size:18px; display:flex; align-items:center; justify-content:space-between; flex-wrap:wrap; gap:12px; } /* Card / block. */ .gbCard { background:var(--card); border:1px solid var(--line); border-radius:0; overflow:hidden; box-shadow:0 1px 2px rgba(20,40,70,.10); margin:12px 0 24px; } /* Horizontal stat/summary strip. */ .gbStrip { display:flex; align-items:center; gap:24px; flex-wrap:wrap; padding:11px 18px; border-bottom:1px solid var(--line); background:var(--panel); } .gbStat { display:flex; flex-direction:column; gap:1px; } .gbStat .k { font-size:12px; color:var(--muted); font-weight:700; } .gbStat .v { font-size:14px; font-weight:700; color:var(--ink); } .gbDiv { width:1px; height:28px; background:var(--line); } .gbStripActions { margin-left:auto; display:flex; gap:8px; align-items:center; flex-wrap:wrap; } /* Buttons - square (radius 0), navy primary, white secondary. Scoped to .gbApp and .subheadingBar * so the framework's link styles (which would add an underline) can't beat them. */ .gbApp .gbPill, .subheadingBar .gbPill, .gbApp .gbStripActions input[type=submit], .gbApp .gbStripActions input[type=button] { font-family:inherit; font-size:13px; font-weight:700; color:var(--btnText); background:var(--btn); border:1px solid var(--btnLine); border-radius:0; padding:5px 12px; cursor:pointer; text-decoration:none; display:inline-block; line-height:1.5; } .gbApp .gbPill:hover, .subheadingBar .gbPill:hover, .gbApp .gbStripActions input[type=submit]:hover, .gbApp .gbStripActions input[type=button]:hover { background:var(--btnHover); text-decoration:none; } .gbApp .gbPill.primary, .subheadingBar .gbPill.primary { background:var(--btnDark); color:#fff; border-color:var(--btnDark); } .gbApp .gbPill.primary:hover, .subheadingBar .gbPill.primary:hover { background:var(--btnDarkHover); } /* In the gold header the framework's link styles would otherwise beat .gbPill; re-assert with * id-level specificity (the framework's title lives in #sectTtl). */ .subheadingBar #sectTtl .gbPill { color:#003a72; background:#fff; border:1px solid #999; text-decoration:none; } .subheadingBar #sectTtl .gbPill:hover { background:#eef2f7; text-decoration:none; } .subheadingBar #sectTtl .gbPill.primary { background:#0a2b6b; color:#fff; border-color:#0a2b6b; } .subheadingBar #sectTtl .gbPill.primary:hover { background:#0a2350; } /* A muted/danger pill variant for destructive actions (Delete). */ .gbApp .gbPill.danger { color:#8b1a1a; } .gbApp .gbPill.danger:hover { background:#fdf2f2; border-color:#b45a5a; } /* Steel-blue section bar - white bold title. */ .gbSection { background:var(--section); color:#fff; padding:6px 13px; font-size:15px; font-weight:700; margin:0 0 14px; } /* Experimental "try the new / classic page" banner. */ .gbBanner { background:#fbf3e2; border:1px solid var(--titleLine); padding:10px 14px; margin:12px 0 0; font-size:14px; color:var(--ink); } .gbBanner a { color:var(--accent); } .gbBanner a:hover { color:var(--accentHover); } /* Share / copy-link row. */ .gbShareBox { display:flex; align-items:center; gap:10px; flex-wrap:wrap; padding:11px 18px; border-bottom:1px solid var(--line); background:var(--panel); } .gbShareMsg { font-size:14px; color:var(--muted); } .gbShareFull { flex:1 1 100%; } .gbShareInput { flex:1; min-width:260px; font-size:13px; padding:5px 8px; border:1px solid var(--btnLine); border-radius:0; background:#fff; } /* Modal dialog - fixed full-viewport backdrop centering a square white card. Keep the markup a DOM * descendant of the .gbApp wrapper so the tokens inherit in. */ .gbModalBg { position:fixed; top:0; right:0; bottom:0; left:0; z-index:1000; background:rgba(0,0,0,.4); display:flex; align-items:center; justify-content:center; } .gbModal { background:#fff; border:1px solid var(--line); border-radius:0; box-shadow:0 4px 18px rgba(0,0,0,.28); padding:18px 20px; min-width:340px; max-width:92vw; } .gbModalTitle { font-size:16px; font-weight:700; color:var(--ink); margin-bottom:12px; } .gbModalText { font-size:13px; color:var(--ink); line-height:1.5; max-width:430px; margin-bottom:14px; } .gbModalText.gbModalNote { margin-top:14px; } .gbModalText a { color:var(--accent); } .gbModalText a:hover { color:var(--accentHover); } .gbModalLabel { display:block; font-size:12px; font-weight:700; color:var(--muted); margin:10px 0 3px; } .gbModalInput { width:100%; box-sizing:border-box; border:1px solid var(--btnLine); border-radius:0; padding:6px 8px; font-size:14px; font-family:inherit; background:#fff; } .gbModalBtns { display:flex; gap:8px; justify-content:flex-end; margin-top:18px; } /* Generic dense results table - steel-tint header, zebra rows, navy selection bar. Apply class * "gbTable" to the <table>; the tool may add its own column classes. */ .gbTable { font-size:13px; width:100%; border-collapse:collapse; } .gbTable thead th { background:var(--headrow); border-bottom:1px solid var(--headrowLine); font-size:12px; color:var(--navy); font-weight:700; padding:8px 12px; white-space:nowrap; text-align:left; } .gbTable tbody td { padding:8px 12px; border-bottom:1px solid var(--lineSoft); white-space:nowrap; vertical-align:middle; } .gbTable tbody tr:nth-child(even) { background:var(--stripe); } .gbTable tbody tr:hover { background:var(--hover); } .gbTable tbody tr.gbSel { background:var(--sel); box-shadow:inset 3px 0 0 var(--navy); } .gbTable td.num, .gbTable th.num { text-align:right; font-variant-numeric:tabular-nums; } .gbTable a { color:var(--accent); text-decoration:none; } .gbTable a:hover { color:var(--accentHover); text-decoration:underline; } + +/* Timing dialog (gbShowTimingDialog in utils.js): a wider modal holding a gbTable whose last column + * is a proportional bar. Shown when a page is loaded with &measureTiming=1. */ +.gbModal.gbTimingModal { max-width:560px; } +.gbTimingTable td.gbTimeBarCell { width:45%; } +/* The bar track fills the cell; the fill width is set inline as a percentage of the total time. */ +.gbTimeBar { position:relative; height:14px; background:var(--stripe); } +.gbTimeBar > span { position:absolute; top:0; left:0; height:100%; background:var(--section); } +.gbTimingTable tr.gbTimeTotal td { font-weight:700; border-top:2px solid var(--headrowLine); } +.gbTimingTable tr.gbTimeTotal .gbTimeBar > span { background:var(--navy); } +/* A subhead row separating the "server" and "client" groups. */ +.gbTimingTable tr.gbTimeGroup td { background:var(--headrow); color:var(--navy); font-weight:700; + font-size:12px; }