Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: switch DnD to modern context API (was legacy) #1819

Merged
merged 10 commits into from
Mar 3, 2021
Merged

fix: switch DnD to modern context API (was legacy) #1819

merged 10 commits into from
Mar 3, 2021

Conversation

ehahn9
Copy link
Collaborator

@ehahn9 ehahn9 commented Nov 29, 2020

DnD addon was relying on legacy context api which finally broke with React 17 (couldn't resize events, etc.).

Fixes #1795. Related to #1776.

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Nov 29, 2020

Hmmm... might still have remaining v17 compatibility issues due to DnD's use of findDOMNode (deprecated). Working on that too.

@jquense
Copy link
Owner

jquense commented Dec 1, 2020

let me know when you want to merge 👍

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Dec 2, 2020

Thanks, @jquense -- the context switch was easy. The use of deprecated findDOMNode is harder (am working on that now).

The original DnD addon is looking like it needs some serious love (very non-DRY, odd js idioms throughout) -- I might take a crack some rejuvenation throughout, but I also want to see it working with React 17 asap.

I'll ping you when I have something useful to review!

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Dec 7, 2020

Hi @jquense... I just realized that the examples build on github seem to be of a different vintage than those on master? (for example, the page's dropdown is missing more recently-added examples).

I've been working on finishing up the DnD refresh and thought I had introduced a regression but noticed that the examples built from master have the same probs (!).

I'll dive into this but wondering if you had thoughts on why the examples page is out-of-date? (or maybe I'm missing something...)

@jquense
Copy link
Owner

jquense commented Jan 4, 2021

@ehahn9 i just always forget to deploy new docs which is why they are out of date. we should make that automatic with the version release tho

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Jan 26, 2021

HI @jquense - I [finally, sorry] had a chance to work on this. Many changes:

  1. Use modern react context API (was legacy)
  2. Uses refs rather than findDOMNode throughout the addin (although alas there is a bunch in the main rbc code, thus preventing react strict mode...)
  3. Moved the DnD readme to the top-level of the addin (was buried in code comment)
  4. Storybook: updated to v6, respect allDay in events
  5. Fixed event propagation bugs (seen only in react 17)
  6. Fixed a number of bounding box and fencepost errors in WeekView
  7. Changed the HOC to extend, rather than repeat propTypes and defaultProps

I had hoped to do a LOT more (css modules for scoped addon classnames, and major cleanup of original implementation which is difficult to maintain) -- maybe I'll get back to that at some point!

I'm still a newbie, so apologies if this PR needs more work (happy to try!).

@yann-combarnous
Copy link

@jquense, any chance you could review and possibly merge this PR? With DND resize broken in react 17, would be great to have it fixed.

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Feb 21, 2021

Hi @jquense - oh apologies - I'm new to this and I wasn't even aware that this was waiting on me. Sorry for asking for a lesson in OSS, but what's the protocol when one is reviewing their own PR? Do I just click squash + merge or should others be reviewing first/also? thx.

@jquense
Copy link
Owner

jquense commented Feb 22, 2021

@ehahn9 generally you still want someone else to review it, but i've not been prompt on that sorry!

@jquense
Copy link
Owner

jquense commented Feb 22, 2021

There is a lot of different fixes and changes here that make it a bit hard to review all at once. Generally its better to split these things into separate PR's, e.g. one for event propagation bugs, one for context changes, etc.

Copy link
Owner

@jquense jquense left a comment

Choose a reason for hiding this comment

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

lots of great work, sorry i'm having a hard time following it!

@@ -55,7 +55,7 @@ class Dnd extends React.Component {

const nextEvents = events.map(existingEvent => {
return existingEvent.id == event.id
? { ...existingEvent, start, end }
? { ...existingEvent, start, end, allDay }
Copy link
Owner

Choose a reason for hiding this comment

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

doesn't the existingEvent already have this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

The old story's moveEvent handler did't honor changes affecting allDay. This change purports to make it possible to demo moving events in and out of the allDay gutter - supported by DnD but previously not supported by the story as it ignored the new value for allDay.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

I should have done this as a separate PR for sure! Newbie/learning.

this.update(event, slotMetrics.getRange(currentSlot, end, false, true))
const { duration } = eventTimes(event, accessors)
let newEnd = dates.add(newSlot, duration, 'milliseconds')
this.update(event, slotMetrics.getRange(newSlot, newEnd, false, true))
Copy link
Owner

Choose a reason for hiding this comment

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

I'm not sure i understand what the changes in this file are fixing? can you walk me through it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Good catch. The problem I was addressing was that the addon would sometimes fail to update the event end on a move. This change always sets end = start + duration where start = newSlot (e.g. the target time slot at the end of the move).


EventContainerWrapper.propTypes = propTypes
render() {
return <div ref={this.ref}>{this.renderContent()}</div>
Copy link
Owner

Choose a reason for hiding this comment

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

i don't think spliting renderContent out as a separate function adds much? maybe just have render().

On the another note, I think it might more more sense to pass the ref to children instead of adding a new DOM element

Copy link
Collaborator Author

@ehahn9 ehahn9 Feb 22, 2021

Choose a reason for hiding this comment

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

Absolutely right. I was having trouble forwarding the ref and took the coward's way out. I'll try to work on this.

this.context.draggable.onBeginAction(this.props.event, 'resize', 'DOWN')
}
handleResizeLeft = e => {
if (e.button !== 0) return
e.stopPropagation()
Copy link
Owner

Choose a reason for hiding this comment

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

It seems like removing these would create bugs, not fix them? Can you walk me through why this is necessary?

Copy link
Collaborator Author

@ehahn9 ehahn9 Feb 22, 2021

Choose a reason for hiding this comment

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

Ok, this one is tricky. the Dnd addon uses rbc's selectable() mechanism to monitor mouse events before/during drags. selectable needs to see those events in order to work. The event wrapper stopped the propagation and so the selection logic was basically broken.

So first, I removed the stop propagation - that helped a lot.

But because the resize anchors are on top of the drag (move) anchor, clicking on a resize would also start a drag/move, which would abort the resize, etc.

So I added a check (see :42) to ignore this case:

    // hack: because of the way the anchors are arranged in the DOM, resize
    // anchor events will bubble up to the move anchor listener. Don't start
    // move operations when we're on a resize anchor.
    const isResizeHandle = e.target.className.includes('rbc-addons-dnd-resize')
    if (!isResizeHandle)
      this.context.draggable.onBeginAction(this.props.event, 'move')

Now the million dollar question is why did this ever work? My only theory is that react 17 changed where the event listeners were placed and maybe that subtle changed the event propagation?

I would love to back all of this out, but it seemed to be required both in reading the code and trying it.

Copy link
Owner

Choose a reason for hiding this comment

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

sounds like you got it all handled 👍

@@ -79,42 +61,34 @@ class WeekWrapper extends React.Component {
this.setState({ segment })
}

handleMove = ({ x, y }, node, draggedEvent) => {
handleMove = (point, bounds, draggedEvent) => {
Copy link
Owner

Choose a reason for hiding this comment

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

All the changes in this file are hard to follow (though i'm sure correct and needed). What is is going on here, and how should test that it works?

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Purely idiomatic: all the other event handlers had the (point, bounds) signature (as does the similar code in EventContainerWrapper) so I was just conforming the idiom.

BTW, if you look closely, you'll see that WeekWrapper and EventContainerWrapper are in DIRE need of being DRY'ed out -- they basically do the same exact thing, with the main difference being the orientation of the event (horizontal or vertical). I spent a few days on that, but had to abandon due to time.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

... oh, and the other changes (sorry, that's probably what you were asking about) - were all about making the date handling correct during drags - which had a number of probs, some of which might have been introduce with the (required) upgrade to date-arithmetic (which was out-of-date and causing some probs).

Happy to answer in more detail about these edits although my memory is fading a bit on this.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

testing: I think the only way is via storybook/examples -- the code seems too intertwined IMHO for proper testing (definitely a good should a rewrite occur!)

Copy link
Owner

Choose a reason for hiding this comment

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

fine to defer the testing if there isn't a good way to write a unit test. I was thinking of the common-ish case where we fix one of these date bounds issues and introduce another one, partly because the calculations have no tests asserting their current behavior so easy to break stuff!

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Feb 22, 2021

I'll wait to hear back from you (@jquense) before working further on this PR. Agreed, I really should have done this in more atomic pieces (and will next time!). Alas, I find the DnD addon to be super hard to work on (maybe even a rewrite) and so my energy was flagging during this... apologies.

Copy link
Owner

@jquense jquense left a comment

Choose a reason for hiding this comment

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

I would rename the PR so semantic release doesn't call all of this a "fix", might be worth hand rebasing the commits into different messages and then doing a "merge" instead of a "squash" but up to you.

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Mar 2, 2021

Thanks @jquense - just to be sure I'm doing the right thing: are you suggesting I replace this PR with smaller, more focussed ones? (I presume there's a way to cancel this PR?) I'm happy to work on that! I know there's some time pressure for this due to v17 so I hope I'm not holding things up.

@jquense
Copy link
Owner

jquense commented Mar 2, 2021

just to be sure I'm doing the right thing: are you suggesting I replace this PR with smaller, more focussed ones? (I presume there's a way to cancel this PR?)

not quite, the suggestion was to rebase the commits in the current PR to something like

  • fix: event propagation bugs
  • fix: drag and drop bounds issues
  • fix: update to modern context

etc, etc, and then merging instead of squash and merge so the commits stay intact on master. That said it all involves a bunch of Git-fu, that you may or may not be comfortable with, so fine to merge as is if you want

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Mar 3, 2021

Just rebased all the commits and reworded - lmk if this looks okay to you -- then I'm happy to merge (merge commit, no squash)

@jquense
Copy link
Owner

jquense commented Mar 3, 2021

very nice 👍

@ehahn9 ehahn9 merged commit 611a0ce into jquense:master Mar 3, 2021
@github-actions
Copy link

github-actions bot commented Mar 3, 2021

🎉 This PR is included in version 0.33.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

@jquense
Copy link
Owner

jquense commented Mar 3, 2021

🎉 very nice

@nlevchuk
Copy link
Contributor

nlevchuk commented Mar 5, 2021

@ehahn9 @jquense Thank you guys for your work

@yann-combarnous
Copy link

yann-combarnous commented Mar 9, 2021

@ehahn9 , @jquense , thx for this! Any chance dnd could be made to work with touch events at some stage?

Dragging works but the initial event selection is very hard to get to work, takes generally a few seconds to manage selection.

@ehahn9
Copy link
Collaborator Author

ehahn9 commented Mar 9, 2021

@yann-combarnous - although more knowledgeable folks might disagree, I suspect the addon might be at the limits of maintainability at this point :-(.

ps: I took a stab at rewriting it from scratch as a completely separate project using react-dnd, but ran into some architectural problems with resize animation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants