Skip to content

fix: data preview pagination, fixed columns and sidebar sizing - #33

Merged
HTHou merged 6 commits into
apache:mainfrom
CritasWang:fix/data-preview-pagination-and-ui-polish
Jul 31, 2026
Merged

fix: data preview pagination, fixed columns and sidebar sizing#33
HTHou merged 6 commits into
apache:mainfrom
CritasWang:fix/data-preview-pagination-and-ui-polish

Conversation

@CritasWang

Copy link
Copy Markdown
Contributor

What this changes

A UI pass over the viewer, plus the backend fix behind the broken data-preview pagination.

Fixes

Data preview was stuck on the first page. DataService.previewData() reads only offset + limit rows to bound memory, then reported the number of rows it had read as total. Reading exactly offset + limit rows is indistinguishable from "the dataset ends here", so hasMore was always false and the page count the UI derived from total was always 1 — no row past the first page was reachable. A 102-row file reported total=100, hasMore=false at offset=0.

The reader now takes one extra row, probed to decide hasMore and never returned. The DTO field documents what it actually is: rows materialized, equal to the filtered total only once the reader ran dry, a lower bound while hasMore is true. On the client DataTable drops the total prop and derives paging from offset/limit/hasMore, with prev/next in place of the page-number control. The row range reads Rows 1-100 while more pages exist and Rows 101-102 of 102 on the last page — the first point where the true total is known.

Fixed table columns went transparent during horizontal scroll. Element Plus pins them with position: sticky and gives them background: inherit, so they inherited the transparency index.css applies to .el-table tr/th/td (which exists to avoid a double-layer colour cast against .tc-table-card). Cells from the scrolling area showed through, reading as overlapping text. Fixed columns are painted back to the card colour with a matching hover state. The background can't live in tableStyle.tsheaderCellStyle/rowStyle render as inline styles that outrank any selector — so the two properties that merely duplicated CSS transparency are dropped.

Features / polish

  • Resizable sidebar. Drag handle on the right edge, clamped to 180–480px, persisted to localStorage; double-click resets, arrow keys/Home work when focused. Hidden below lg, where the sidebar is a drawer.
  • Column pager bar right-aligned so it sits with the scrolling area it drives.
  • Time-range picker capped at 372px — the narrowest width that still shows both 19-character endpoints in full (Element Plus defaults datetimerange to 400px).

The first two commits are the Element Plus + Tailwind rewrite this work builds on: the previous stack (antdv-next + UnoCSS) sourced corner radii, control heights, table density and interaction feedback from library defaults that CSS variable overrides alone could not reconcile with the design spec.

Testing

  • pnpm build (includes vue-tsc) and mvn compile pass.
  • Pagination verified end to end against a 102-row file: offset=0 now returns hasMore=true; clicking through lands on Rows 101-102 of 102 with next disabled, and back on page 1 with prev disabled.
  • Fixed columns verified opaque after scrolling 900px, in both light and dark themes.
  • Sidebar drag verified for clamping at both ends, double-click reset and persistence.
  • Confirmed every table using tableStyleProps (including the nested table in ScanReport's expand row) sits inside .tc-table-card, so dropping the inline styles does not change their appearance.

The previous stack (antdv-next + UnoCSS) sourced corner radii, control
heights, table density and interaction feedback from component-library
defaults. Overriding CSS variables alone could not bring them in line
with the design spec.

- Component library: antdv-next -> Element Plus 2.14; 24 components and
  views migrated
- Style engine: UnoCSS -> Tailwind 3, adding tokens.css / index.css and
  an Element Plus SCSS variable override entry point
- Layout: left sidebar (220px) + content area, top bar dropped; the new
  AppSidebar and PageHeader host the file tree and the tool area
- Theme: light / dark / follow-system now driven by html.dark, with a
  deep navy base for dark mode
- Table density factored out into utils/tableStyle.ts for reuse
- Metadata table height is allocated on demand; the scan page gained an
  empty state

Behaviour is unchanged; api/stores/utils/router were not touched.
The error-type bar chart still carried the previous component library's
brand blue (#1677ff), which clashed with the palette every other chart
draws from. Take the palette's first colour instead.
File paths in the tree vary a lot in length, so a fixed 220px sidebar
either wastes horizontal space or truncates names. Add a drag handle on
the right edge, clamped to 180-480px and persisted to localStorage.

Double-click resets to the default width, and the handle is focusable so
arrow keys (16px steps) and Home work too. It is hidden below the lg
breakpoint, where the sidebar is a drawer whose width comes from the
breakpoint. The aside switches from lg:static to lg:relative so the
absolutely positioned handle anchors to it rather than to an outer
element.
previewData() reads only offset+limit rows to bound memory, then reported
the number of rows it had read as `total`. Reading exactly offset+limit
rows is indistinguishable from "the dataset ends here", so hasMore was
always false and the page count the UI derived from `total` was always 1.
No row past the first page was reachable. A 102-row file reported
total=100, hasMore=false at offset=0.

Read one extra row instead. It is probed to decide hasMore and never
returned. The local is renamed to `rowsRead` and the DTO field documents
what it actually is: the number of rows materialized, which equals the
filtered total only once the reader ran dry, and is a lower bound while
hasMore is true. Clients must not derive a page count from it.

On the client, DataTable drops the `total` prop and derives paging from
offset/limit/hasMore, replacing the page-number control with prev/next.
The row range reads "Rows 1-100" while more pages exist and
"Rows 101-102 of 102" on the last page, which is the first point where
the true total is known.
Element Plus pins fixed columns with position: sticky and gives them
`background: inherit`, so they inherited the transparency index.css
applies to `.el-table tr/th/td` to avoid a double-layer colour cast
against .tc-table-card. Cells from the scrolling area showed through
them, which read as overlapping text.

Paint fixed columns back to the card colour and add the matching hover
state, otherwise they stay card-coloured while the rest of the row
highlights. The background cannot be set from tableStyle.ts:
headerCellStyle / rowStyle render as inline styles that outrank any
selector. They only duplicated transparency that CSS already handles, so
they are dropped. The scroll shadow is left to the library's
is-scrolling-* rules.
Two leftovers from the layout pass:

- The column pager bar sat on the left of a full-width row, detached from
  the table's scrolling area it drives. Right-align it.
- Element Plus sizes datetimerange at 400px by default, leaving the time
  range picker stretched across the filter row. Both ends render 19
  characters, so 372px is the narrowest width that still shows them in
  full.
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