fix: data preview pagination, fixed columns and sidebar sizing - #33
Merged
HTHou merged 6 commits intoJul 31, 2026
Merged
Conversation
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.
HTHou
approved these changes
Jul 31, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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 onlyoffset + limitrows to bound memory, then reported the number of rows it had read astotal. Reading exactlyoffset + limitrows is indistinguishable from "the dataset ends here", sohasMorewas always false and the page count the UI derived fromtotalwas always 1 — no row past the first page was reachable. A 102-row file reportedtotal=100, hasMore=falseatoffset=0.The reader now takes one extra row, probed to decide
hasMoreand 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 whilehasMoreis true. On the clientDataTabledrops thetotalprop and derives paging fromoffset/limit/hasMore, with prev/next in place of the page-number control. The row range readsRows 1-100while more pages exist andRows 101-102 of 102on 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: stickyand gives thembackground: inherit, so they inherited the transparencyindex.cssapplies 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 intableStyle.ts—headerCellStyle/rowStylerender as inline styles that outrank any selector — so the two properties that merely duplicated CSS transparency are dropped.Features / polish
localStorage; double-click resets, arrow keys/Home work when focused. Hidden belowlg, where the sidebar is a drawer.datetimerangeto 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(includesvue-tsc) andmvn compilepass.offset=0now returnshasMore=true; clicking through lands onRows 101-102 of 102with next disabled, and back on page 1 with prev disabled.tableStyleProps(including the nested table inScanReport's expand row) sits inside.tc-table-card, so dropping the inline styles does not change their appearance.