Skip to content

feat: Enable horizontal scrolling on search results table#1871

Open
elizabetdev wants to merge 8 commits intomainfrom
search-table-responsive
Open

feat: Enable horizontal scrolling on search results table#1871
elizabetdev wants to merge 8 commits intomainfrom
search-table-responsive

Conversation

@elizabetdev
Copy link
Contributor

@elizabetdev elizabetdev commented Mar 10, 2026

Summary

Closes HDX-2701

Enables horizontal scrolling on the search results table so that column content is no longer clipped when the viewport is narrower than the total column widths.

Changes

  • Dynamic minWidth on the table element — Computes the sum of all column widths from TanStack Table's getSize() (substituting a 200px minimum for the flexible last column) and sets it as an inline min-width on the <table>. When the container is narrower than this threshold, the table overflows and the wrapper scrolls horizontally. When wider, width: 100% ensures the table fills the container normally.
  • min-width: 0 on flex containers — Added miw={0} to the RawLogTable outer <Flex> and the DBSearchPage results/pattern containers so flex children can shrink below their content size, allowing overflow to trigger scrolling.
  • Consolidate utility classes into SCSS module — Moved overflow: auto, height: 100%, and font-size from inline Bootstrap utility classes (overflow-auto, h-100, fs-8) into .tableWrapper, and moved width: 100% !important into .table (replacing the w-100 class).

Files changed

  • packages/app/src/components/DBRowTable.tsx — Added tableMinWidth computation; set inline minWidth on table; added miw={0} to outer Flex; moved utility classes to SCSS
  • packages/app/src/DBSearchPage.tsx — Added miw={0} to results and pattern container Flex wrappers
  • packages/app/styles/LogTable.module.scss — Added overflow, height, font-size to .tableWrapper; added width: 100% !important to .table

Test plan

  • Open the Search page with multiple columns selected (e.g. Timestamp, ServiceName, SeverityText, Body, ScopeName)
  • Narrow the browser window — verify a horizontal scrollbar appears and columns are not cut off
  • Scroll horizontally — verify all column content is accessible
  • Widen the browser window — verify the table fills the container and no unnecessary scrollbar appears
  • Verify the last column still expands to fill remaining space on wide viewports
  • Resize columns via drag handles — verify horizontal scroll adjusts dynamically
  • Verify wrap lines toggle still works correctly
  • Switch to Event Patterns analysis mode — verify no layout regressions
  • Check the table in other contexts (Dashboard tiles, Pattern side panel) to confirm no layout regressions

…SearchPage and RawLogTable

- Added `miw={0}` to Flex components in DBSearchPage to ensure minimum width is set.
- Adjusted className in RawLogTable to remove redundant styles and improve readability.
- Enhanced LogTable styles with overflow and height properties for better layout on small screens.
@changeset-bot
Copy link

changeset-bot bot commented Mar 10, 2026

🦋 Changeset detected

Latest commit: 6fda610

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 3 packages
Name Type
@hyperdx/app Patch
@hyperdx/api Patch
@hyperdx/otel-collector Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@vercel
Copy link

vercel bot commented Mar 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
hyperdx-oss Ready Ready Preview, Comment Mar 10, 2026 1:58pm

Request Review

@github-actions
Copy link
Contributor

github-actions bot commented Mar 10, 2026

PR Review: feat: Enable horizontal scrolling on search results table

⚠️ Duplicated magic number defaults → The column size defaults (isDate ? 170 : isMaybeSeverityText ? 115 : 160) are duplicated verbatim from the column definition logic at line ~581 into the new tableMinWidth computation at line ~699 in DBRowTable.tsx. If one set of defaults changes, the other silently diverges and the min-width calculation will be wrong. Consider extracting these into shared constants (e.g., DEFAULT_DATE_COLUMN_WIDTH, etc.), or use TanStack Table's table.getHeaderGroups()[0].headers.map(h => h.getSize()) to derive widths directly from the table's own state instead of re-implementing the logic.

✅ Everything else looks good — the miw={0} on flex containers, the Bootstrap utility class consolidation into SCSS, and the overall scrolling approach are all correct and follow project patterns. The removed eslint-disable comments are a nice cleanup.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Code Review

The approach is sound — moving overflow: auto / height: 100% to the SCSS module and adding miw={0} to the flex containers is the correct way to enable horizontal scrolling in this component hierarchy.

One issue worth addressing before merge:

  • ⚠️ min-width: 1000px on .table is hardcoded and doesn't reflect actual column widths — The PR description says the table "calculates its minimum width by summing all fixed-width column sizes", but the implementation just uses a static 1000px. With table-layout: fixed, the real column widths are controlled by TanStack's getSize() calls. This means: (a) with few narrow columns, a horizontal scrollbar appears unnecessarily; (b) with many wide columns totaling >1000px, the table can still overflow without triggering a scrollbar because the min-width is already exceeded. The fix is to compute the total column width in RawLogTable and pass it as an inline style={{ minWidth }} on the <table> element (or via a CSS custom property on the wrapper), removing the hardcoded value from the SCSS.

Everything else looks good — the SCSS consolidation is clean, the miw={0} Mantine prop usage is idiomatic, and removing the now-redundant eslint-disable-next-line comments is correct since @typescript-eslint/no-explicit-any is already 'off' in the ESLint config.


Open in Web View Automation 

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Code Review

The approach is correct (overflow on the wrapper + min-width on the table + miw={0} flex fix), and the utility-class-to-SCSS migration and eslint-disable cleanup are clean. One issue worth addressing before merge:

  • ⚠️ Hardcoded min-width: 1000px doesn't match actual column state — The PR description says "calculates minimum width by summing all fixed-width column sizes," but the implementation just uses a static 1000px. With only 1–2 narrow columns selected the table is unnecessarily wide (dead space); with many wide columns 1000px may still be too small to prevent clipping. The actual column widths are already available via TanStack Table's table.getTotalSize() — compute the min-width dynamically in RawLogTable and apply it as an inline style on the table element instead.

✅ No other critical issues found.


Open in Web View Automation 

…lculation

- Implemented a dynamic minimum width calculation for the RawLogTable to enable horizontal scrolling on smaller viewports.
- Updated table styles to ensure proper width handling and prevent the last column from collapsing.
- Adjusted SCSS to enforce a 100% width for the table layout, ensuring consistent rendering across different screen sizes.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Code Review

Overall the approach is sound — miw={0} on the flex containers, computing a pixel minWidth for the table, and consolidating utility classes into the SCSS module are all correct patterns.

Two items worth addressing:

  • ⚠️ useMemo with [table] won't memoizeuseReactTable returns a new object reference on every render, so useMemo(() => ..., [table]) recomputes every render providing zero caching benefit. Either remove the useMemo wrapper, or derive the dependency from the actual column-sizing state (e.g. table.getState().columnSizing).

  • ⚠️ width: 100% !important in SCSS — No inline width style is set on the <table> element (only minWidth), so there's nothing for a normal width: 100% declaration to lose a specificity battle against. The comment is vague about what "overrides" it. !important can silently mask future specificity conflicts; worth verifying this is truly necessary and tightening the comment if so.

✅ All other changes look correct — miw={0} is the right flex fix, the tableMinWidth calculation logic handles the UNDEFINED_WIDTH sentinel correctly, and removing the now-redundant eslint-disable comments is fine since no-explicit-any is globally off in the project's ESLint config.


Open in Web View Automation 

- Enhanced the minimum width calculation for the RawLogTable to accommodate dynamic column sizes and improve responsiveness.
- Updated the table's SCSS to maintain a consistent 100% width without the need for `!important`, ensuring better layout handling across various screen sizes.
Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

✅ No critical issues found.

The implementation is clean and the approach is sound. A few minor observations for awareness:

  • The tableMinWidth useMemo manually mirrors column default widths (170, 115, 160, 32) that are already defined elsewhere in the same file. These are consistent today, but extracting them as shared constants would prevent future drift if defaults change.
  • The PR description mentions width: 100% !important but the actual SCSS uses width: 100% (no !important). This is fine functionally — removing the !important from the old w-100 Bootstrap class is appropriate — but the description is slightly misleading.
  • fs-8var(--mantine-font-size-xs) migration is correct; the project's _utilities.scss confirms these are equivalent.

Open in Web View Automation 

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Stale comment

Code Review

The horizontal scrolling implementation is solid overall. One functional bug and one maintainability concern:

  • ⚠️ Last-column resize ignored in tableMinWidth — When a user has resized the last column (stored in columnSizeStorage), the tableMinWidth useMemo always substitutes MIN_FLEX_COLUMN_WIDTH = 200 for it, ignoring the stored size. If the user resized the last column to e.g. 500px, the computed min-width would be ~300px short of the actual rendered table width, so the horizontal scrollbar may never appear. Fix: check columnSizeStorage[displayedColumns[displayedColumns.length - 1]] and fall back to MIN_FLEX_COLUMN_WIDTH only if absent.

  • ⚠️ Duplicated default column widths — The fallback widths 170 / 115 / 160 in tableMinWidth exactly mirror the defaults already in the column definitions (line 581). If a future change updates those defaults in one place but not the other, the min-width calculation silently diverges from actual rendered widths. Consider extracting shared constants (e.g. DEFAULT_DATE_COL_WIDTH, DEFAULT_SEVERITY_COL_WIDTH, DEFAULT_COL_WIDTH) used in both locations.

✅ Everything else looks good — the Bootstrap utility class consolidation into the SCSS module is clean, the miw={0} flex fixes are correct, and the overflow: auto / height: 100% migration is functionally equivalent.


Open in Web View Automation 

expandWidth +
displayedColumns.reduce((total, column, i) => {
if (i === displayedColumns.length - 1)
return total + MIN_FLEX_COLUMN_WIDTH;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The last column's stored resize value in columnSizeStorage is not checked here — it always uses MIN_FLEX_COLUMN_WIDTH = 200. If the user has resized the last column to a larger value, tableMinWidth will undercount, and the horizontal scrollbar may not appear.

Suggested fix:

const lastCol = displayedColumns[displayedColumns.length - 1];
const lastColSize = columnSizeStorage[lastCol] ?? MIN_FLEX_COLUMN_WIDTH;
return total + lastColSize;

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

✅ No critical bugs or security issues. The approach is sound and the changes are well-scoped.

One thing worth fixing:

  • ⚠️ Duplicated column-size fallback logictableMinWidth (lines 698–699 in DBRowTable.tsx) re-implements the exact same defaults (isDate ? 170 : isMaybeSeverityText ? 115 : 160) already defined in the column definition (line 581). If those defaults ever change in one place, the other won't stay in sync. Consider using TanStack Table's own API after table initialization — e.g. table.getAllColumns().reduce(...) with col.getSize() — or extracting the defaults into a shared constant/helper so there's a single source of truth.

Everything else (SCSS consolidation, miw={0} on flex containers, removing the now-redundant eslint-disable comments) looks correct and follows project patterns.


Open in Web View Automation 

const isDate = jsColumnType === JSDataType.Date;
const isMaybeSeverityText = column === logLevelColumn;
const size =
columnSizeStorage[column] ??
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fallback logic (isDate ? 170 : isMaybeSeverityText ? 115 : 160) is identical to the column definition at line 581. Extract into a shared constant or helper (or use table.getAllColumns() + col.getSize()) to avoid the two falling out of sync.

@teeohhem
Copy link
Contributor

May be an edge case, but if a column is moved over to the right and horizontal scrolling is enabled, I can never see the column even if I scroll. See video.

Search---ClickStack.mp4

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants