Sheets: add "Data has header row" toggle to preserve headers during sort#495
Open
the-narwhal wants to merge 4638 commits into
Open
Sheets: add "Data has header row" toggle to preserve headers during sort#495the-narwhal wants to merge 4638 commits into
the-narwhal wants to merge 4638 commits into
Conversation
Prevent concurrent referral spotlight feature PUTs See merge request web/clients!24282
VPNPLG-58: Add payload and telemetry when forking the session See merge request web/clients!24135
fix: fix icon alignment in cancellation flow See merge request web/clients!24315
Add offer card UI components See merge request web/clients!24302
added temporary need content and config See merge request web/clients!24307
feat: workspace premium cancelation flow See merge request web/clients!24319
Add news subscription for Meet See merge request web/clients!24209
use the same setting menu for extension as for web See merge request web/clients!24241
INWEB-867: Add common setup for Slack API in the CI See merge request web/clients!24271
Add new permissions modals and stop requesting permissions automatically See merge request web/clients!24248
DRVWEB: Search blobs encryption/decryption See merge request web/clients!23888
[IDTEAM-5613]
[IDTEAM-5613] Add telemetry for sharing See merge request web/clients!24221
Limit sharing settings visibility only to admins on parent share See merge request web/clients!24326
[DRVWEB-4974] Album listing sdk See merge request web/clients!23946
Enable telemetry for Meet See merge request web/clients!24331
Prevent missing navigator.mediaDevices to throw See merge request web/clients!24429
Update category counts when labelling a message from a conversation See merge request web/clients!24325
Update openSubscriptionModal usage See merge request web/clients!24107
Fix a bug storing feature flags in cookie See merge request web/clients!24454
[DRVWEB-4967] delete legacy drive view See merge request web/clients!24263
NOISSUE: Adapt telemetry for tv flow See merge request web/clients!24405
Defer update prompt if user is in meeting See merge request web/clients!24450
Mail BYOE: hide lock icons in sent messages when `X-Pm-Byoe` header is present See merge request web/clients!24000
PostQuantumOptInModal: prompt for auth before committing the opt-in See merge request web/clients!24457
Add LoginLink member creation mode See merge request web/clients!24448
Sorting a column via "Sort A to Z" / "Sort Z to A" was sorting the entire sheet including row 1, destroying column header labels. This adds an opt-in toggle under Data → Sort that, when enabled, excludes row 1 from all sort operations. Changes ------- ui-state.ts - Add `hasHeaderRow` boolean state (default false — existing behaviour unchanged unless the user explicitly enables the toggle) - Add `toggleHeaderRow` event setter (stable ref via `useEvent`) - Branch `sortAscending` / `sortDescending`: when `hasHeaderRow` is true, call `onSortRange` with a range starting at row 2 instead of calling `onSortColumn` for the full column - Expose `hasHeaderRow` and `toggleHeaderRow` on the `data` slice of the UI state so all sort entry points share a single source of truth sort-utils.ts (new) - Extract `makeSortRangeExcludingHeader(rowCount, columnCount)` as a pure function so the range-building logic can be unit-tested without importing @rowsncolumns/* packages sort-utils.test.ts (new) - 8 unit tests covering typical sheets, single-column sheets, header-only sheets (edge: empty range), and large sheets DataMenu.tsx - Add "Data has header row" menu item inside the Sort submenu with a checkmark indicator and proper i18n context string ContextMenu.tsx / LegacyContextMenu.tsx - Extract stable `sortAscending` / `sortDescending` refs at component top level (fixes implicit Rules-of-Hooks violation from inline hooks inside JSX event props) - Route "Sort A to Z" / "Sort Z to A" buttons through `useUI.$.data.sortAscending` / `sortDescending` so the header-row toggle is respected in both new and legacy UI modes
3a2ffcb to
8b49cee
Compare
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.
Due to the constraints of working outside the full Proton development environment, I was not able to build or run the application locally to verify this end-to-end. The implementation follows all established codebase patterns and passes TypeScript diagnostics, but it has not gone through a full build pipeline or staging environment test. This is intended as a reference implementation Proton is welcome to merge, incorporate, or iterate on it as needed.
Summary
Adds a "Data has header row" toggle to the Sort submenu (Data → Sort) in Proton Sheets. When enabled, row 1 is excluded from sort operations so column headers stay in place. When disabled (the default), sort behavior is identical to before, no regression for existing users.
This addresses a community feature request where using "Sort A to Z" or "Sort Z to A" on a column would sort the entire sheet including row 1, destroying header labels.
What changed
ui-state.tscore logichasHeaderRow: booleanstate (defaultfalse, so existing sort behaviour is completely unchanged unless the user explicitly enables the toggle)toggleHeaderRowa stable event ref viauseEvent()that flips the flagsortAscendingandsortDescending: whenhasHeaderRowistrue, callsonSortRangewith a range starting at row 2 instead ofonSortColumnon the full column; whenfalse, falls through to the original callhasHeaderRowandtoggleHeaderRowon thedataslice of the UI state so every sort entry point (menu bar, context menu, legacy context menu) shares a single source of truth without any duplicated logicsort-utils.ts(new file)Extracts
makeSortRangeExcludingHeader(rowCount, columnCount)as a pure function with no@rowsncolumns/*dependencies. This keeps the range-building logic independently testable and documents the intentional edge case (a sheet with only one row produces an empty range callers treat it as a no-op).sort-utils.test.ts(new file)8 unit tests covering:
startRowIndexis always 2 regardless of sheet sizestartColumnIndexis always 1endRowIndex/endColumnIndexreflect the provided dimensionsThese follow the existing test pattern in the codebase (pure utility functions only, no component harness needed).
DataMenu.tsxnew UI toggleselectedIndicator={hasHeaderRow}for the checkmark, matching the pattern used in the View menuleadingIndentkeeps it visually nested under the sort actionssheets_2025:Spreadsheet editor menubar data menu (sort submenu)contextContextMenu.tsxandLegacyContextMenu.tsxrouting + hooks fixsortAscendingandsortDescendingrefs at component top level (same pattern already used forinsertLinkin both files)onClickhandlers were inline arrow functions callinguseUI.$inside JSX, which is not valid under React's hooks rulesuseUI.$.data.sortAscending/sortDescending, so thehasHeaderRowcheck inui-state.tsis respected from every sort trigger in both the new and legacy UIBehaviour
onSortRangewithstartRowIndex: 2, keeping row 1 fixedThe toggle is session-local (resets on page reload). Persisting it to user preferences would be a natural follow-up.
What has and hasn't been tested
makeSortRangeExcludingHeaderunit tests (8 cases)node_modulesavailableSuggested manual verification steps