Skip to content

Conversation

@gimmyhehe
Copy link
Member

@gimmyhehe gimmyhehe commented Dec 13, 2025

PR

修复visibleColumn变化时,会删除掉新插入数据问题

PR Checklist

Please check if your PR fulfills the following requirements:

  • The commit message follows our Commit Message Guidelines
  • Tests for the changes have been added (for bug fixes / features)
  • Docs have been added / updated (for bug fixes / features)

PR Type

What kind of change does this PR introduce?

  • Bugfix
  • Feature
  • Code style update (formatting, local variables)
  • Refactoring (no functional changes, no api changes)
  • Build related changes
  • CI related changes
  • Documentation content changes
  • Other... Please describe:

What is the current behavior?

Issue Number: N/A

What is the new behavior?

Does this PR introduce a breaking change?

  • Yes
  • No

Other information

Summary by CodeRabbit

  • New Features

    • Added a grid toolbar with local-storage persistence and a personalization/settings panel to toggle column visibility.
  • Bug Fixes

    • Improved editable-row field normalization, revert/load behavior, and data fallbacks to ensure consistent restore, editing, and display.
  • Tests

    • Expanded tests for grid customization, column visibility toggling, row editing, and improved selector scoping.
  • Style

    • Adjusted header column styling affecting which resizable divider is hidden.

✏️ Tip: You can customize this high-level summary in your review settings.

@github-actions github-actions bot added the bug Something isn't working label Dec 13, 2025
@coderabbitai
Copy link

coderabbitai bot commented Dec 13, 2025

Walkthrough

Adds a TinyGridToolbar to a demo grid; shifts internal restore/load sources to prefer rawData; derives editable columns from tableFullColumn and normalizes fields when that set changes; expands a demo test to toggle column visibility via the personalization panel.

Changes

Cohort / File(s) Summary
Toolbar integration (demo)
examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value-composition-api.vue, examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.vue
Import and register TinyGridToolbar from @opentiny/vue; add a <TinyGridToolbar> template inside the TinyGrid configured with local-storage settings.
Demo test: personalization panel
examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.spec.js
Add locator for custom grid panel; create a new row, open personalization/settings panel, toggle visibility of the "地址" column, assert column hidden, re-check row count and editable behavior.
Composable: editable-columns & normalization
packages/vue/src/grid/src/composable/useNormalData.ts
Change param from visibleColumntableFullColumn; add editorColumns and editorColumnKey; watch tableFullColumn to derive editable columns; call table.defineField and bump rawDataVersion when editable set changes; normalize raw/insert rows.
Edit revert source change
packages/vue/src/grid/src/edit/src/methods.ts
_revertData now reads from rawData (instead of tableSynchData) when reverting/reloading rows without explicit arguments.
Table methods: field definition & data sources
packages/vue/src/grid/src/table/src/methods.ts
loadTableData no longer assigns tableSynchData; defineField signature extended to (row, copy, editorColumns, cache) and updates origin rows when adding editable fields; getData fallback uses [] instead of this.tableSynchData; getRowById considers editStore.insertMap.
Table init: useNormalData argument
packages/vue/src/grid/src/table/src/table.ts
Pass tableFullColumn (not visibleColumn) into useNormalData.
Styling tweak
packages/theme/src/grid/header.less
Change nth-last-of-type selector from 2 → 1 for header column resizable line hiding.
Misc / manifest
package.json
Listed in manifest (no functional change described).

Sequence Diagram(s)

sequenceDiagram
  participant Demo as Demo (TinyGrid)
  participant Toolbar as TinyGridToolbar
  participant Table as Table instance
  participant Composable as useNormalData
  participant Editor as Edit methods

  Demo->>Toolbar: render toolbar (localStorage settings)
  Demo->>Table: initialize table (pass tableFullColumn)
  Table->>Composable: useNormalData({ props, tableFullColumn })
  Composable->>Composable: derive editorColumns from tableFullColumn
  Composable->>Table: call table.defineField(row, copy, editorColumns, cache)
  Note right of Table: defineField may add fields and sync origin rows when editorColumns changes
  User->>Demo: trigger edit or revert
  Demo->>Editor: invoke revert/edit
  Editor->>Table: _revertData reads from rawData and reloads rows
  Table->>Demo: updated rows/state rendered
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Inspect watcher/key derivation and normalization in packages/vue/src/grid/src/composable/useNormalData.ts.
  • Verify defineField signature change and origin-row synchronization in packages/vue/src/grid/src/table/src/methods.ts.
  • Confirm _revertData behavior in packages/vue/src/grid/src/edit/src/methods.ts and interactions with load/getData changes.
  • Review demo/test selector robustness and timing around the personalization panel.

Poem

🐇 I nibble keys and polish rows tonight,
Tiny toolbar hums with stored delight,
Columns hide, editors wake anew,
Raw fields stitched back where old syncs once flew,
Hop, click, save — a tiny grid in view.

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed Title references fixing visible column changes deleting insert rows, which aligns with changes to useNormalData, defineField, and related data handling logic throughout the PR.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch cgm/fix-visible-column-change

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 55356c7 and e2e96d0.

📒 Files selected for processing (1)
  • packages/vue/src/grid/src/table/src/methods.ts (4 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/vue/src/grid/src/table/src/methods.ts
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
packages/vue/src/grid/src/edit/src/methods.ts (1)

254-285: Avoid reloading with possibly-undefined rawData
If this.rawData can ever be undefined/non-array, return this.reloadData(rawData) (Line 284) can behave like “clear”. Normalize once and reuse.

  _revertData(rows, field) {
-    let { rawData } = this
+    const rawData = Array.isArray(this.rawData) ? this.rawData : []
 
     if (arguments.length && rows && !isArray(rows)) {
       rows = [rows]
     }
 
     if (!arguments.length) {
-      rows = rawData || []
+      rows = rawData
     }
@@
-    return this.reloadData(rawData)
+    return this.reloadData(rawData)
   },
packages/vue/src/grid/src/table/src/methods.ts (1)

753-765: getData() should not ignore tableFullData when rawData is unset/stale
const allRows = this.rawData || [] (Line 754) can return [] even when tableFullData is populated (e.g., via loadTableData). Safer fallback:

  getData(rowIndex) {
-    const allRows = this.rawData || []
+    const allRows = this.rawData || this.tableFullData || []
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5bdfec1 and 154b322.

📒 Files selected for processing (6)
  • examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value-composition-api.vue (2 hunks)
  • examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.spec.js (2 hunks)
  • examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.vue (2 hunks)
  • packages/vue/src/grid/src/composable/useNormalData.ts (2 hunks)
  • packages/vue/src/grid/src/edit/src/methods.ts (2 hunks)
  • packages/vue/src/grid/src/table/src/methods.ts (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)
🔇 Additional comments (6)
packages/vue/src/grid/src/composable/useNormalData.ts (2)

3-21: Watcher split matches the bugfix intent (don’t reload on column changes)
Good change: rawDataVersion bumps only on rawData updates (Line 10-21), avoiding unintended reloads from column-visibility changes. Consider a small safety guard to avoid runtime errors if $table isn’t ready:

-  const $table: any = hooks.getCurrentInstance()?.proxy
+  const $table: any = hooks.getCurrentInstance()?.proxy
@@
-      _data.forEach((row) => $table.defineField(row))
+      $table && _data.forEach((row) => $table.defineField(row))

23-33: Ensure insertList rows are normalized without triggering a data reload
This watcher (Line 23-33) looks correct for the reported issue: it updates row shape for rawData and editStore.insertList while not bumping rawDataVersion (so inserted rows shouldn’t be dropped).

packages/vue/src/grid/src/table/src/methods.ts (1)

290-317: loadTableData() intentionally does not update rawData—document its contract to prevent API misuse.

The current design uses separate data paths: loadTableData() updates tableFullData for display (e.g., filtered data in select/grid-select), while rawData remains the source of truth. External callers in select and grid-select do not call getData() after loadTableData(), so no active bug exists. However, the API contract is unclear. Future developers may incorrectly assume getData() reflects changes from loadTableData(). Consider:

  1. Document loadTableData() as an internal method intended only for display updates (e.g., filtering) that do not affect the source data.
  2. Alternatively, update getData() to fall back to tableFullData when rawData is unavailable or stale, ensuring consistency.
examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.spec.js (1)

7-51: Selector scoping and test isolation concerns require HTML structure verification

The test does use page.locator('.tiny-grid-custom__setting-btn') without scoping to demo, which could cause cross-demo collisions if multiple grid instances exist on the page. However, the proposed fix of scoping to demo.locator('.tiny-grid-custom__setting-btn') assumes the settings button is a child of the demo container—this needs verification against the actual HTML structure.

Regarding localStorage: Playwright does not clear localStorage by default on page.goto(), so persisted column visibility settings could cause test flakiness across runs. However, localStorage.clear() is only necessary if the grid customization state is actually stored in localStorage.

Before applying the suggested fixes, confirm:

  • Whether .tiny-grid-custom__setting-btn is nested inside the demo element or is a global component
  • Whether the grid custom settings are persisted via localStorage or session state
examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.vue (2)

28-28: LGTM!

The import statement correctly includes TinyGridToolbar, which is necessary for the new toolbar functionality.


35-36: LGTM!

Component registrations are correct. Both TinyButton (which was previously used in the template) and the newly added TinyGridToolbar are now properly registered.

Comment on lines +5 to +7
<template #toolbar>
<tiny-grid-toolbar id="undefined-field-defalut-value" :setting="{ storage: 'local' }"></tiny-grid-toolbar>
</template>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Typo in the toolbar ID attribute.

The ID contains "defalut" instead of "default". While this is consistent with the filename, it's still a typo that should be corrected.

Apply this diff to fix the typo:

       <template #toolbar>
-        <tiny-grid-toolbar id="undefined-field-defalut-value" :setting="{ storage: 'local' }"></tiny-grid-toolbar>
+        <tiny-grid-toolbar id="undefined-field-default-value" :setting="{ storage: 'local' }"></tiny-grid-toolbar>
       </template>

Note: You may also want to rename the file itself to maintain consistency.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<template #toolbar>
<tiny-grid-toolbar id="undefined-field-defalut-value" :setting="{ storage: 'local' }"></tiny-grid-toolbar>
</template>
<template #toolbar>
<tiny-grid-toolbar id="undefined-field-default-value" :setting="{ storage: 'local' }"></tiny-grid-toolbar>
</template>
🤖 Prompt for AI Agents
In
examples/sites/demos/pc/app/grid/data-source/undefined-field-defalut-value.vue
around lines 5 to 7, the toolbar id contains a typo "defalut" instead of
"default"; update the id attribute value to "undefined-field-default-value" to
correct the spelling, and optionally rename the file to
examples/sites/demos/pc/app/grid/data-source/undefined-field-default-value.vue
(and update any imports/references) to keep filename consistent with the
corrected id.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 154b322 and 32c7a26.

📒 Files selected for processing (3)
  • packages/vue/src/grid/src/composable/useNormalData.ts (1 hunks)
  • packages/vue/src/grid/src/edit/src/methods.ts (2 hunks)
  • packages/vue/src/grid/src/table/src/table.ts (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/vue/src/grid/src/edit/src/methods.ts
🧰 Additional context used
🧬 Code graph analysis (1)
packages/vue/src/grid/src/table/src/table.ts (1)
packages/vue/src/grid/src/composable/useNormalData.ts (1)
  • useNormalData (3-69)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: PR E2E Test (pnpm test:e2e3)
🔇 Additional comments (6)
packages/vue/src/grid/src/composable/useNormalData.ts (5)

3-3: LGTM! API signature updated correctly.

The refactoring from visibleColumn to tableFullColumn aligns with the PR objective to fix the issue where changing visibleColumn would delete newly inserted rows. By tracking the full column set instead of just visible columns, the data normalization can react properly to column visibility changes.


4-4: LGTM! Explicit typing improves clarity.

Adding the explicit type annotation for $table improves code readability, even though it's typed as any.


9-11: LGTM! New state for tracking editable columns.

The introduction of editorColumns and editorColumnKey enables the new logic to track which columns are editable and react to changes in the editable column set.


47-59: LGTM! Raw data normalization logic is sound.

The watcher correctly normalizes fields for rawData only (not insertList), as indicated by the comment that temporary insert data will be cleaned up later. The version increment triggers downstream cache updates and data handling via the existing rawDataVersion watcher.


34-45: No conflict between watchers—the design is intentional.

The editorColumns watcher processes both insertList and rawData because column structure changes require normalizing all data. The subsequent rawData watcher explicitly excludes insertList, as documented in its inline comment: "不处理临时插入数据,因为后续会被清理掉" (doesn't process insertList because it will be cleaned up later). The insertList is cleared when table data is loaded via loadTableData(), confirming it's temporary and the design is sound.

packages/vue/src/grid/src/table/src/table.ts (1)

711-711: LGTM! Integration point updated correctly.

The change from visibleColumn to tableFullColumn correctly aligns with the refactored useNormalData API. This enables the data normalization logic to track all columns (not just visible ones), which should fix the reported issue where changing visibleColumn would delete newly inserted rows.

Comment on lines 13 to 32
hooks.watch(tableFullColumn, (_tableFullColumn) => {
let columns = []
let columnKeys = []

for (let i = 0; i < _tableFullColumn.length; i++) {
const column = _tableFullColumn[i]

if (column.property && column.editor) {
columns.push(column)
columnKeys.push(column.propety)
}
}

const keyString = columnKeys.sort().join()

if (editorColumnKey.value !== keyString) {
editorColumnKey.value = keyString
editorColumns.value = columns
}
})
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Critical typo: column.propety should be column.property.

Line 22 contains a typo that will cause the columnKeys array to collect undefined values, breaking the key comparison logic and potentially causing incorrect behavior when columns change.

Apply this diff to fix the typo:

       if (column.property && column.editor) {
         columns.push(column)
-        columnKeys.push(column.propety)
+        columnKeys.push(column.property)
       }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
hooks.watch(tableFullColumn, (_tableFullColumn) => {
let columns = []
let columnKeys = []
for (let i = 0; i < _tableFullColumn.length; i++) {
const column = _tableFullColumn[i]
if (column.property && column.editor) {
columns.push(column)
columnKeys.push(column.propety)
}
}
const keyString = columnKeys.sort().join()
if (editorColumnKey.value !== keyString) {
editorColumnKey.value = keyString
editorColumns.value = columns
}
})
hooks.watch(tableFullColumn, (_tableFullColumn) => {
let columns = []
let columnKeys = []
for (let i = 0; i < _tableFullColumn.length; i++) {
const column = _tableFullColumn[i]
if (column.property && column.editor) {
columns.push(column)
columnKeys.push(column.property)
}
}
const keyString = columnKeys.sort().join()
if (editorColumnKey.value !== keyString) {
editorColumnKey.value = keyString
editorColumns.value = columns
}
})
🤖 Prompt for AI Agents
In packages/vue/src/grid/src/composable/useNormalData.ts around lines 13 to 32
there is a typo: column.propety is used when pushing keys which yields
undefined; change that to column.property so columnKeys collects the actual
property values (ensure the push uses column.property and nothing else needs
changing).

@gimmyhehe gimmyhehe changed the title fix(grid): fix visible columns change delete insert row fix(grid): fix visible columns change wloud delete insert row Dec 16, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (1)
examples/sites/demos/pc/app/grid/custom/column-simple.spec.js (1)

7-7: Prefer role-based selectors for better test resilience.

The shift from getByRole('listitem') to CSS class selector .tiny-option-label makes the test more brittle. Role-based selectors are Playwright's recommended approach—they're semantic, accessibility-focused, and less likely to break when implementation details change.

Consider reverting to role-based selectors:

-  await page.locator('.tiny-option-label').filter({ hasText: '员工数' }).click()
+  await page.getByRole('listitem', { name: '员工数' }).click()
-  await page.locator('.tiny-option-label').filter({ hasText: '名称' }).click()
+  await page.getByRole('listitem', { name: '名称' }).click()

If the UI lacks proper ARIA roles, consider fixing the component markup instead of downgrading the test selectors.

Also applies to: 10-10

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 526ebce and 4435df8.

📒 Files selected for processing (2)
  • examples/sites/demos/pc/app/grid/custom/column-simple.spec.js (1 hunks)
  • examples/sites/demos/pc/app/grid/editor/custom-editor-select.spec.js (1 hunks)
🔇 Additional comments (1)
examples/sites/demos/pc/app/grid/editor/custom-editor-select.spec.js (1)

6-10: No changes needed. Line 9 correctly uses page.locator('.tiny-option-label') because the select component's dropdown options are rendered in the document body by default (via popperAppendToBody: true), not within the demo container. The demo.locator() scoping on preceding lines applies only to elements within the component; using page.locator() for portal elements rendered outside is the intended pattern.

Likely an incorrect or invalid review comment.

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants