Skip to content

fix: improve formbuilder logic#1135

Merged
3mcd merged 14 commits into
mainfrom
tfk/formbuilder-fixes
Apr 22, 2025
Merged

fix: improve formbuilder logic#1135
3mcd merged 14 commits into
mainfrom
tfk/formbuilder-fixes

Conversation

@tefkah
Copy link
Copy Markdown
Member

@tefkah tefkah commented Apr 3, 2025

  • fix: improve client side logic for formbuilder
  • fix: be able to submit access changes on their own

Issue(s) Resolved

Resolves #1143

High-level Explanation of PR

Roughly does 3 things:

  1. Moves the form builder diff calculation on the client, that way it's easier to only send up changes that are relevant, and we disable the submit button if no changes have been made
  2. Updates access if that is the only thing changed. Previously also the formelements needed to have been moved/deleted/added in order for a change in access to go through
  3. slight beauty enhancements

Moving diff to client

This was put as TODOs in the code in some places, and it made my life easier, so i did.

The main change to the diffing algorithm is here:

https://github.com/pubpub/platform/blob/23a047bdf927b2c8a4d10f42a41626b6976a66b1/core/app/components/FormBuilder/FormBuilder.tsx#L155-L164

May be a better way of doing this but i thought this was fine for now (i expect the order of keys to be relatively stable).

Basically, if nothing except maybe the id/updatedAt of the form element has changed, we do not consider it a change.

Note

Caveat: A "rank" change is still considered a change. If two elements are swapped back and forth, their rank may still have been changed. I find it hard to check for this case as i'll admit i don't fully understand the ranking implementation, maybe @kalilsn you have some insight on how to ignore swapping back and forth cases.

Warning

Moving the diffs to the client now does carry slightly more risk for weird stuff happening, but not really that much more than before

Update logic changes

Since all the changes now arrive as separate entities, we can more easily only update form accesstype if that has changed.

QoL changes

  • When hovering over the drag handle, we now show cursor-drag rather than cursor-pointer
  • When dragging, we now show cursor-dragging, rather than cursor-pointer
  • When dragging, the dragged element no longer sometimes slides under other elements when dragged.

Demo:
(slightly hard to see bc recording my screen apparently makes the cursor almost always be the default one)

Screen.Recording.2025-04-14.at.12.14.28.mov

Test Plan

Screenshots (if applicable)

Notes

Comment on lines -31 to -38
searchParams: Promise<{
unsavedChanges: boolean;
}>;
}) {
const searchParams = await props.searchParams;

const { unsavedChanges } = searchParams;

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this logic does not need to happen server side, we can just do it client side. this is much faster

Comment on lines +162 to +164
if (JSON.stringify(defaultElement) === JSON.stringify(elementWithoutUpdated)) {
return acc;
}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

very sophisticated diffing. please recommend a better approach if you know one

const form = useForm<FormBuilderSchema>({
resolver: zodResolver(formBuilderSchema),
values: {
const [isChanged, setIsChanged] = useIsChanged();
Copy link
Copy Markdown
Member Author

@tefkah tefkah Apr 14, 2025

Choose a reason for hiding this comment

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

this is a small custom nuqs hook reads from/updates the isChanged query param. using nuqs we can do this without a round trip to the server, which we want. this is because shallow is set to true by default. maybe i should add that option to make it slightly more clear that these are client-side only url updates

https://github.com/pubpub/platform/blob/415de673452e7952872c1d341ebfc01f3da8054c/core/app/components/FormBuilder/useIsChanged.tsx#L1-L13

type="submit"
data-testid="save-form-button"
disabled={disabled}
disabled={disabled != null ? disabled : !isChanged}
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

maybe i should just remov the disabled prop entirely and make it !isChanged by default

Comment on lines +175 to +178
if (
element.relatedPubTypes.length === 0 &&
defaultElement.relatedPubTypes?.length
) {
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

i added this defaultElement.relatedPubTypes?.length check, bc otherwise if you swapped a relation element back and forth it would assume something had to be deleted, which didn't make sense

@tefkah tefkah requested review from allisonking and kalilsn April 14, 2025 10:50
@tefkah tefkah marked this pull request as ready for review April 14, 2025 10:51
Copy link
Copy Markdown
Contributor

@allisonking allisonking left a comment

Choose a reason for hiding this comment

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

woo this is awesome! approving, though I don't know about the ranking part either though, so maybe wait for Kalil to weigh in on that part?

@3mcd 3mcd merged commit bfd67ba into main Apr 22, 2025
16 checks passed
@3mcd 3mcd deleted the tfk/formbuilder-fixes branch April 22, 2025 17:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bug: cannot make form public

3 participants