feat(profile-dist): datetime cell — classifier consolidation + intra-day tooltips (DRC-3669 + DRC-3670)#1451
Conversation
formatEpochSeconds rendered DATE-ONLY (UTC), so a paired histogram over an
intra-day timestamp column produced information-free tooltips like
"Jun 5, 2026 - Jun 5, 2026". Add an optional `includeTime` param appending a
UTC HH:mm (true) or HH:mm:ss ("seconds") clock time, and have the cell's
datetime branch pick the precision from the bin-edge span:
- span >= 1 day -> date only (unchanged)
- span < 1 day -> date + HH:mm
- span < 1 min -> date + HH:mm:ss
Histogram components are untouched: the cell still passes a (v)=>string
formatValue closure. Flips the formatTime.test collapse assertion to
intra-day-distinctness + multi-day-day-only cases, and adds a
PairedHistogramDatetime story with seconds / minutes / days scales (each
surfaces the real bars' tooltips for visual review).
Draft exploration branch for DRC-3670 visual review.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Danyel Fisher <danyel@gmail.com>
… (DRC-3669) Part A of the DRC-3669/3670 datetime-cell work. Replaces the two local substring heuristics (isDatetimeType/isTimeOfDayType) in InlineProfileDistributionCell with the canonical classifyType classifier, so the cell and the DataTypeIcon glyph share one source of truth. - Add DuckDB TIMESTAMP_S/_MS/_NS to CATEGORY_MAP (previously fell through to 'unknown', the gap that forced the local substring helpers). - Route the histogram branch via classifyType with a null-guard (classifyType has no null-guard but columnType is optional): time -> formatTimeOfDay; date|datetime -> the span-aware makeEpochFormatter (DRC-3670 intra-day path); else -> no special formatting. - Tests: TIMESTAMP_S/_MS/_NS -> datetime; TIME/TIMETZ stay time. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
Code Review: PR #1451 — DRC-3669 + DRC-3670SHA Targeted suite green from Should-fix
Notes
What I verified clean
|
… gap; ClickHouse types; vitest coverage (DRC-3670) Addresses PR #1451 self-review findings: - should-fix #1: makeEpochFormatter now derives time precision from the minimum gap between adjacent merged (base∪current, sorted, de-duped) edges instead of the total span, so individual narrow segments no longer collapse to identical labels (e.g. 14:30-14:30). Empty/single-edge and NaN-edge cases still no-op gracefully via the existing Number.isFinite filter. - should-fix #2: add real vitest coverage (jsdom render + read bar <title>s) for the intra-day HH:mm branch, sub-minute HH:mm:ss branch, the min-gap distinctness behavior, the multi-day date-only branch, and the empty-edges fallback. These run under 'pnpm test' (root vitest), not just Storybook. - review note #3: classifyType CATEGORY_MAP gains ClickHouse DATE32 -> date and DATETIME64 -> datetime (incl. DATETIME64(3, 'UTC') via paren-strip), with tests. Also DRYs the DRC-3670 Storybook datetime fixtures/stories onto a single makeContinuousDatetimeFixture factory and a single makeDatetimeStory factory, and updates them to demonstrate the new min-gap precision behavior. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Signed-off-by: Danyel Fisher <danyel@gmail.com>
gcko
left a comment
There was a problem hiding this comment.
- LOW: Sub-second timestamp bins can still collapse to identical tooltip labels even though this PR now classifies DuckDB
TIMESTAMP_MSandTIMESTAMP_NSas datetime types. The formatter selects onlyHH:mm:sswhen the merged edge gap is below 60 seconds, andformatEpochSecondshas no millisecond or fractional-second branch, so edges such as14:30:00.100and14:30:00.900both render as14:30:00. This is a tooltip precision gap, not data corruption, but it leaves a visible edge case in the newly supported sub-second timestamp path; the new tests cover 10-second gaps but not fractional-second gaps. Citations:js/packages/ui/src/components/ui/DataTypeIcon/classifyType.ts:82,js/packages/ui/src/components/data/InlineProfileDistributionCell.tsx:167,js/packages/ui/src/utils/formatTime.ts:161,js/packages/ui/src/components/data/__tests__/InlineProfileDistributionCell.test.tsx:326.
What this PR does
Fixes two small, related problems with the datetime column display in the profile-distribution cell (the inline mini-histogram you see for a column). They're bundled together because they touch the same file. Both came out of the review of PR #1381/#1411 and were picked up during the June backlog-cleanup pass (Linear DRC-3669 and DRC-3670).
Part A — One source of truth for "is this column a date/time?" (DRC-3669)
The problem. The histogram cell had its own little helper functions for guessing whether a column is a date, a time, or a timestamp — separate from the app's main type classifier (
classifyType). Two copies of the same logic is a maintenance trap: they drift apart, and a fix in one doesn't reach the other.Why two copies existed. The main classifier didn't recognize DuckDB's sub-second timestamp types (
TIMESTAMP_S,TIMESTAMP_MS,TIMESTAMP_NS) — it returned "unknown" for them. To work around that, someone gave the cell its own substring-based guesser. So the duplication was a symptom of a gap in the real classifier.The fix. Close the gap, then delete the duplicate:
classifyTypeabout the three DuckDB timestamp types so they classify asdatetime(this also fixes the type icon for those columns as a bonus).classifyTypeinstead — one classifier for the whole app.classifyTypeassumes it's handed a real string, but the cell's column type can be undefined while a cell is still loading. So the call is guarded (columnType ? classifyType(columnType) : "unknown") — without it, the cell would crash.Part B — Timestamp tooltips that actually tell you something (DRC-3670)
The problem. Histogram tooltips for timestamp columns only showed the date, never the time. For data that all lands on a single day — which is normal for event logs loaded in one batch — every bar's tooltip read the same useless string: "Jun 5, 2026 – Jun 5, 2026."
The fix. Show the time of day in the tooltip, but only when it helps. The formatter looks at how wide the histogram's overall time span is and adapts:
HH:mmHH:mm:ssTimes stay in UTC throughout (the backend emits UTC seconds; rendering in local time would shove day-boundary values onto the wrong calendar day).
The two parts meet cleanly: once Part A routes datetime columns through the shared classifier, that path feeds Part B's span-aware formatter.
Files changed
classifyType.ts— addTIMESTAMP_S/_MS/_NS → datetime.InlineProfileDistributionCell.tsx— drop the two local helpers; route throughclassifyType(guarded); build the span-aware time formatter.formatTime.ts—formatEpochSecondsgains an optionalincludeTimeflag (UTC preserved).classifyType.test.ts,InlineProfileDistributionCell.test.tsx,formatTime.test.ts.How to see it
PairedHistogramDatetime.stories.tsx(Storybook) renders the tooltip at three scales — seconds, minutes, days — so you can eyeball the labels across spans.Tests
Full
js/suite green on push: 1939 passed, 5 skipped.tsc --noEmitclean, Biome lint clean.Known limitation (separate decision, not fixed here)
The paired histogram is percentile-based: each environment is binned on its own quantile edges (intentional — DRC-3389 / PR #1398 — because the backend returns approximate quantiles, not bin counts, so base and current genuinely can't share bin edges without giving up the fast approximate-percentile path). The two staircases share a value axis but not edge positions, so where a base edge and a current edge sit close together you get a thin "filler" segment whose two ends round to the same label (e.g.
14:30–14:30). The new precise time labels just make this pre-existing behavior visible. Suppressing those sub-precision segments (cosmetic) is a separate call — flagging, not fixing, here.Checklist
pnpm test,pnpm type:check,pnpm lint)🤖 Generated with Claude Code