Skip to content

feat: add onAddRow button to EditableTable and nested rows#3576

Open
laurafg wants to merge 4 commits intomainfrom
feature/add-rows
Open

feat: add onAddRow button to EditableTable and nested rows#3576
laurafg wants to merge 4 commits intomainfrom
feature/add-rows

Conversation

@laurafg
Copy link
Contributor

@laurafg laurafg commented Mar 3, 2026

🚪 Why?

The EditableTable visualization in f0 needs an "Add row" affordance so consumers can let users insert new rows directly from the table UI — both at the root level and within nested/expandable rows. Additionally, the generic TableCollection API should not be coupled to editable-table-specific props.

🔑 What?

  • Add an optional onAddRow callback to EditableTable that renders a ghost "Add row" button in the table footer and at the bottom of each expanded nested row. The callback receives the parent item when triggered from a nested row (undefined at root level) and supports async functions for automatic loading state.
  • Add addRowButtonLabel and nestedAddRowButtonLabel props to customize the button text at root and nested levels, falling back to an i18n default.
  • Introduce AddRowContext provided by EditableTableCollection, replacing prop drilling of add-row concerns through TableCollection -> Row -> NestedRow and keeping the generic table API clean.
  • Add unit tests for Table (add-row via context) and NestedRow (nested add-row via context).
  • Add Storybook stories: flat editable table with functional row insertion, nested table with action logging, and editable table combining summary row with add-row.
Screen.Recording.2026-03-03.at.13.29.04.mov

Copilot AI review requested due to automatic review settings March 3, 2026 12:23
@laurafg laurafg force-pushed the feature/add-rows branch from 9222b61 to c99b941 Compare March 3, 2026 12:24
@github-actions github-actions bot added the react Changes affect packages/react label Mar 3, 2026
@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

✅ No New Circular Dependencies

No new circular dependencies detected. Current count: 0

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

🔍 Visual review for your branch is published 🔍

Here are the links to:

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

📦 Alpha Package Version Published

Use pnpm i github:factorialco/f0#npm/alpha-pr-3576 to install the package

Use pnpm i github:factorialco/f0#c0affb29b2444282ec540b84bf9cd7b55ee8784d to install this specific commit

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR introduces an Editable Table visualization for experimental/OneDataCollection, enabling inline cell editing (starting with text) and adding extensibility hooks to the existing TableCollection (row wrapper, cell renderer, add-row actions, separate visualization settings key).

Changes:

  • Added a new editableTable visualization type + registry entry, with dedicated i18n keys and Storybook docs/stories.
  • Extended TableCollection with customization hooks (rowWrapper, cellRenderer, showItemActions, visualizationSettings, onAddRow) to support wrappers like EditableTable without duplicating table logic.
  • Added a ui/value-display editor contract + registry, plus a TextEditor implementation used by the editable table cell renderer.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/react/src/ui/value-display/types/text/text-editor.tsx Adds TextEditor implementation using existing Input field.
packages/react/src/ui/value-display/types/text/index.tsx Exports TextEditor from the text value-display type barrel.
packages/react/src/ui/value-display/types.ts Introduces ValueDisplayEditorProps contract for editor components.
packages/react/src/ui/value-display/index.tsx Re-exports editor registry from value-display entrypoint.
packages/react/src/ui/value-display/editors.ts Adds valueDisplayEditors registry + EditableValueDisplayType.
packages/react/src/lib/providers/i18n/i18n-provider-defaults.ts Adds default translations for editable table visualization + add-row/error strings.
packages/react/src/experimental/OneDataCollection/visualizations/collection/types.ts Adds editableTable to visualization type union.
packages/react/src/experimental/OneDataCollection/visualizations/collection/collectionViewRegistry.tsx Registers the new editableTable visualization + settings handling keyed by editableTable.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/types.ts Adds customization prop types (rowWrapper, cellRenderer, showItemActions, visualizationSettings, onAddRow).
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/settings/handleResetSettings.ts Removes dedicated reset handler in favor of inline reset in registry.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/settings/SettingsRenderer.tsx Allows passing a visualization settings key into table settings UI.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/providers/NestedProvider.tsx Persists nested expansion state in context to survive parent re-renders.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/index.tsx Updates exports after removing reset handler file.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/components/TableSettings.tsx Adds visualizationKey support so column settings are stored under table vs editableTable.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/components/Row.tsx Adds optional cellRenderer and forwards nested wrapping/add-row props down to NestedRow.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/components/NestedRow.tsx Moves provider responsibility to table-level context and adds nested “Add row” UI.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/tests/Table.spec.tsx Adds tests for cellRenderer, rowWrapper, and showItemActions.
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/Table.tsx Wires customization props into TableCollection, mounts nested provider, and adds root-level “Add row” footer.
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/types.ts Defines editable table column/options types and onCellChange contract.
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/index.tsx Exports EditableTable visualization and supporting context/renderer helpers.
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/context/EditableRowContext.tsx Adds per-row optimistic editing state, per-cell loading/errors, and change handling.
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/components/EditableCellRenderer.tsx Implements editable cell rendering via valueDisplayEditors and row context.
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/EditableTable.tsx Wraps TableCollection with EditableRowProvider and EditableCellRenderer to enable editing.
packages/react/src/experimental/OneDataCollection/stories/visualizations/editable-table/editable-table.stories.tsx Adds Storybook examples for editable table usage, settings, errors, nested, and add-row behavior.
packages/react/src/experimental/OneDataCollection/stories/visualizations/editable-table/editable-table.mdx Adds MDX documentation for the Editable Table visualization.
packages/react/src/experimental/OneDataCollection/stories/visualizations.mdx Adds “Editable Table” entry to the visualizations docs index.
packages/react/src/experimental/OneDataCollection/stories/mockData.tsx Extends mock visualizations to include editable table + cache update helper and refetch dependencies.
Comments suppressed due to low confidence (2)

packages/react/src/experimental/OneDataCollection/stories/visualizations/editable-table/editable-table.stories.tsx:17

  • This new story meta is missing the standard tags used across OneDataCollection stories (e.g. ["autodocs", "experimental"]). Also add a Snapshot story using withSnapshot({}) to match the repo Storybook checklist and ensure Chromatic coverage.
const meta = {
  title: "Data Collection/Visualizations/Editable Table",
  parameters: {
    layout: "padded",
    docs: {

packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/Table.tsx:335

  • TableWrapper is only NestedDataProvider when tableWithChildren is truthy, but tableWithChildren is currently derived from data?.records (flat data only). In grouped mode you can still render NestedRow, and useNestedDataContext() will throw because the provider isn’t mounted. Consider mounting NestedDataProvider whenever nested rows are possible (e.g. when source.itemsWithChildren is defined), or compute tableWithChildren for both flat and grouped data.
  const TableWrapper = tableWithChildren ? NestedDataProvider : Fragment

@laurafg laurafg changed the title Feature/add rows feat: add onAddRow button to EditableTable and nested rows Mar 3, 2026
@github-actions github-actions bot added the feat label Mar 3, 2026
@laurafg laurafg force-pushed the feature/add-rows branch from c99b941 to 0d3b3f2 Compare March 3, 2026 14:08
Add an optional `onAddRow` callback to EditableTable that renders a
ghost "Add row" button at the bottom of the table and at the bottom of
each expanded nested row. The callback receives the parent item when
triggered from a nested row (undefined at root level) and supports
async functions for automatic loading state via F0Button.

- Add `onAddRow` to EditableTableVisualizationOptions and
  TableCustomizationProps types
- Propagate through Table → Row → NestedRow with proper depth-based
  indentation using SPACING_FACTOR
- Add i18n key `collections.editableTable.addRow`
- Add stories: flat table with functional row insertion, nested table
  with action logging

Made-with: Cursor
Copilot AI review requested due to automatic review settings March 3, 2026 14:10
@laurafg laurafg force-pushed the feature/add-rows branch from 0d3b3f2 to 7b189fa Compare March 3, 2026 14:10
@laurafg laurafg marked this pull request as ready for review March 3, 2026 14:10
@laurafg laurafg requested a review from a team as a code owner March 3, 2026 14:10
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

@github-actions
Copy link
Contributor

github-actions bot commented Mar 3, 2026

Coverage Report for packages/react

Status Category Percentage Covered / Total
🔵 Lines 42.98% 8742 / 20338
🔵 Statements 42.32% 8973 / 21202
🔵 Functions 33.97% 1928 / 5675
🔵 Branches 32.84% 5261 / 16020
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/EditableTable.tsx 11.11% 100% 0% 11.11% 50-91
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/types.ts 100% 100% 100% 100%
packages/react/src/experimental/OneDataCollection/visualizations/collection/EditableTable/context/AddRowContext.tsx 100% 100% 100% 100%
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/Table.tsx 74.19% 52.25% 60.71% 74.44% 55-71, 223-227, 395, 437, 468-546, 563, 587-666
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/components/NestedRow.tsx 85.96% 78.12% 90% 85.96% 129, 158, 240, 261-289, 316-323
packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/components/Row.tsx 100% 74.28% 100% 100%
packages/react/src/lib/providers/i18n/i18n-provider-defaults.ts 100% 100% 100% 100%
Generated in workflow #11510 for commit 1cce251 by the Vitest Coverage Report Action

…ableTable

Allow consumers to customize the "Add row" button text at both
root and nested levels. When not provided, the existing i18n
default is used.

Made-with: Cursor
Copy link
Collaborator

@sauldom102 sauldom102 left a comment

Choose a reason for hiding this comment

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

Some visual feedback, maybe we could better align cells to be centered

Image

Copilot AI review requested due to automatic review settings March 5, 2026 20:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 3 comments.

Comments suppressed due to low confidence (1)

packages/react/src/experimental/OneDataCollection/visualizations/collection/Table/Table.tsx:627

  • The summary row is rendered as sticky bottom-0 even when an additional footer row (onAddRow) is appended after it. This can cause the sticky summary row to visually overlap/obscure the “Add row” button (since both want to occupy the bottom area). Consider updating the footer layout so only the last footer row is bottom-0 (e.g., make the add-row row sticky at bottom-0 and offset the summary row above it, or disable stickiness when onAddRow is present).
          {(summaryData || onAddRow) && (
            <TableFooter>
              {summaryData && (
                <TableRow
                  className={cn(
                    summaryData.sticky &&
                      "sticky bottom-0 z-10 bg-f1-background shadow-[0_-1px_0_0_var(--f1-border-secondary)] hover:bg-f1-background",
                    "font-medium"
                  )}
                >

Comment on lines +278 to +282
const addRowButtons = screen.getAllByRole("button", { name: /add row/i })
expect(addRowButtons.length).toBeGreaterThanOrEqual(2)

// The first "Add row" button in DOM order is the one inside the nested row
await user.click(addRowButtons[0])
Copy link

Copilot AI Mar 5, 2026

Choose a reason for hiding this comment

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

Clicking addRowButtons[0] depends on DOM order, which can change (e.g. if footer order changes, or other “Add row” buttons are introduced). To make the assertion robust, scope the query to the expanded nested section (e.g. using within(...) on a container row/cell that is part of the expanded area) and click the button found within that scope.

Copilot uses AI. Check for mistakes.
Replace prop drilling of onAddRow, addRowButtonLabel, and
nestedAddRowButtonLabel through TableCollection -> Row -> NestedRow
with a React context provided by EditableTableCollection. This keeps
the generic Table API clean of editable-table-specific concerns.

Made-with: Cursor
Copilot AI review requested due to automatic review settings March 6, 2026 14:32
@laurafg laurafg force-pushed the feature/add-rows branch from 741314f to 1cce251 Compare March 6, 2026 14:32
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.

Comment on lines +1 to +4
import { screen, waitFor } from "@testing-library/react"
import userEvent from "@testing-library/user-event"
import { describe, expect, it, vi } from "vitest"

Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This new test file uses a .spec.tsx suffix, but packages/react/AGENTS.md specifies tests must be named .test.ts/.test.tsx (never .spec.ts). Please rename this file accordingly so it follows the repo’s testing conventions.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +1185 to +1189
describe("onAddRow", () => {
it("does not render add-row button when onAddRow is not provided", async () => {
render(
<TableCollection<
Person,
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

This file is named Table.spec.tsx, but packages/react/AGENTS.md states test files should be .test.ts/.test.tsx (never .spec.ts). Since this PR adds new tests here, consider renaming the file to align with the project’s testing conventions.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines +371 to +373
style={{
marginLeft: `${((props.nestedRowProps?.depth ?? 0) + 1) * SPACING_FACTOR}px`,
}}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

The nested add-row indentation re-implements the depth * SPACING_FACTOR calculation inline. To keep indentation consistent with the rest of the nested-table rendering (and avoid duplicating spacing logic), prefer using the existing getNestedMarginLeft(...) helper from TableCell/utils/nested instead of computing the pixel value manually here.

Copilot uses AI. Check for mistakes.
Comment on lines +69 to +74
<AddRowProvider
value={{
onAddRow: onAddRow as AddRowProviderProps["value"]["onAddRow"],
addRowButtonLabel,
nestedAddRowButtonLabel,
}}
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

onAddRow is cast to the context type when building the AddRowProvider value. This assertion sidesteps TypeScript’s function-parameter variance checks and can hide real type mismatches. Consider changing the AddRowContext API to avoid needing a cast (e.g., store an (parentItem?: unknown) => ... callback in context and provide a typed useAddRow<R>() hook that narrows it at consumption time, similar to EditableRowContext).

Copilot uses AI. Check for mistakes.
Comment on lines +46 to 48
import { useAddRow } from "../EditableTable/context/AddRowContext"
import { statusToChecked } from "../utils"
import { Row } from "./components/Row"
Copy link

Copilot AI Mar 6, 2026

Choose a reason for hiding this comment

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

PR description mentions adding onAddRow to TableCustomizationProps, but the implementation wires add-row behavior through AddRowContext (no onAddRow prop on TableCustomizationProps in Table/types.ts). Please update the PR description to match the actual approach, or update the types if the intent is to expose this through TableCustomizationProps.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat react Changes affect packages/react

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants