DataViews: Fix mismatch between local state and nested data in DataForm modal panel#71384
DataViews: Fix mismatch between local state and nested data in DataForm modal panel#71384straku wants to merge 5 commits intoWordPress:trunkfrom
DataForm modal panel#71384Conversation
|
Warning: Type of PR label mismatch To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.
Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task. |
|
The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message. To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook. |
|
👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @straku! In case you missed it, we'd love to have you join us in our Slack community. If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information. |
|
Looking at tests now, they are passing locally for me 👀 EDIT: I didn't rebase with |
ac1cfad to
22072c5
Compare
opr
left a comment
There was a problem hiding this comment.
I feel like having to flatten data is not ideal, but the other alternative of implementing asetValue does seem worse in comparison, putting additional friction on the user. Thanks for investigating them both.
I did leave one minor comment about type checking, but from my end I think this approach is fine and keeps the implementation details away from the user.
| const { flattenedData, modifiedFields } = useMemo( () => { | ||
| // It will be a mix of original structure for fields without getValue, | ||
| // and a flattened object in shape of { [fieldId]: fieldValue } | ||
| const newFlattenedData: { [ key: string ]: any } = {}; |
There was a problem hiding this comment.
any is fine here because getValue ultimately returns any?
There was a problem hiding this comment.
Yes, since getValue return value is typed as any I used it here too.
| const newFlattenedData: { [ key: string ]: any } = {}; | ||
|
|
||
| const newModifiedFields = fields.map( ( field ) => { | ||
| if ( field.getValue ) { |
There was a problem hiding this comment.
should this check be tighter and check if it's a function too?
| if ( field.getValue ) { | |
| if ( field.getValue && typeof field.getValue === 'function' ) { |
There was a problem hiding this comment.
I would go in the opposite direction—I am not sure if we should gate it at all. In the fields normalization process, this function is always provided (even if not used by customers); see:
|
Hi @straku thanks for taking the time, this is great work.
There's another use case where nested data is problematic, see #70957 We need to fix this, it's worth looking into implementing As I see it:
{
id: 'name',
getValue: ( { item } ) => item.user.name,
setValue: ( { item, edits } ) => { /* handle setting the name in item.user.name */ }
}
{
id: 'user.name'
// Field doesn't need to provide getValue / setValue functions
// that work with the nested value. We create them for the field in normalizeFields.
}How does it sound for you? |
|
@oandregal Sounds great! I will follow up with another PR in the next few days. |
What?
openAswith thedropdownandmodaloptions was introduced in #71212. Unfortunately, we've discovered a problem with this functionality when used with nested data andgetValue. The local state within the modal that holds "pending" changes (they get propagated through theonChangeprop only when you click the "Apply" button in the modal) was storing the flattened data structure for each field (the one you get whengetValueis called with the data object) instead of the nested one thatDataFormexpects.Why?
Let's look at an example with pseudocode:
As you can see above,
dataToDisplayis a mix of nested and shallow data.DataFormdisplays the one that's still not edited.How?
I've tried two approaches to fix it:
DataForm(this PR implements it)setValuefunction in the field API that will be required alongsidegetValuespecifically for modals. It works, and implementation is cleaner, but:setValueto process what we report back inonChangetoo)Testing Instructions
I've added unit tests, but I didn't add a specific story within Storybook for this case, as it wouldn't add value apart from the possibility to test it easier here. You can add it locally for testing purposes only.
packages/dataviews/src/components/dataform/stories/index.story.tsxin your editornpm run storybook:dev)Story to copy & paste
Testing Instructions for Keyboard
Screenshots or screencast
The example shown in the screencast is using nested data with
getValuefor each of its fields.CleanShot.2025-08-28.at.11.53.30.mp4