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

✨ Allow adding all lists of a user to workspace #220

Merged
merged 7 commits into from
Nov 18, 2024
Merged

Conversation

foysalit
Copy link
Contributor

Screenshot 2024-10-17 at 10 12 30

await addItemsToWorkspace(nextLists.data.lists.map((f) => f.uri))
cursor = nextLists.data.cursor
// if the modal is closed, that means the user decided not to add any more user to workspace
} while (cursor && isConfirmationOpen)
Copy link
Contributor

@matthieusieben matthieusieben Oct 17, 2024

Choose a reason for hiding this comment

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

Due to the nature of how react works, this condition will not actually cancel the loop as isConfirmationOpen is a const that will never become false.

For this to work you'll probably need to rely on a ref & AbortController.

const runController = ref<AbortController | null>(null)
const isWorking = abortRef.current != null

const startWorking = async () => {
  // Get a reference to the previous run controller before we replace it with our own
  const prevController = runController.current

  const controller = new AbortController()
  runController.current = controller

  // Abort previous run, if any
  prevController?.abort()

  const { signal } = controller
  try {
    do {
      await someAsyncStuff({
        signal
      })
    } while (!signal.aborted)


    if (signal.aborted) {
      // make sure the catch block is triggered
      throw signal.reason
    }
  } catch (err) {
    if (signal.aborted) {
      toast.info('this action was aborted')
    } else {
      toast.error(`Something went wrong: ${(e as Error).message}`)
    }
  } finally {
    // Prevent re-use (for good measure)
    controller.abort()

    // If this run is still the currently active one
    if (runController.current === controller) {
      // Cleanup reference
      runController.current = null

      // Close the modal
      setIsConfirmationOpen(false)
    }
  } 
}

const abortCurrentRun = () => {
  // No need to call setIsConfirmationOpen here as this will be done through startWorking's finally block
  runController.current?.abort()
}

// Abort the current run when the component is unmounted (e.g. due to navigation)
useEffect(() => {
  return () => runController.current?.abort()
}, [runController])

PS: If this feels too manual, the mutation lib probably already does all of the above

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah I knew it wasn't optimal but it does kill the requests if other conditions cause a re-render.
we use this pattern in a few places so I cleaned up all usage of this pattern to use abort controllers. thank you for pointing it out!

@@ -112,27 +122,42 @@ function useSearchResultsQuery(q: string) {
return
}
setIsAdding(true)
const newAbortController = new AbortController()
Copy link
Contributor

Choose a reason for hiding this comment

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

For good measure, we should ensure that only one run is possible at any given time.

Suggested change
const newAbortController = new AbortController()
// allready running
if (abortController.current) return
const newAbortController = new AbortController()

or

Suggested change
const newAbortController = new AbortController()
// user cancelled by confirming again
abortController.current?.abort('user-cancelled')
const newAbortController = new AbortController()

Copy link
Contributor Author

Choose a reason for hiding this comment

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

hmm... not sure how this case could happen since every interaction aborts the controller after it is instantiated. especially with the abort on unmount. I will give it another look when refactoring these into a hook.

Copy link
Contributor

Choose a reason for hiding this comment

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

It shouldn't happen, but only because the isAdding UI prevents it to. So if someone else breaks that code (eg. by changing the UI), it might end-up happening in parallel. Adding this is just a safety measure against future changes.

Copy link
Contributor

@matthieusieben matthieusieben left a comment

Choose a reason for hiding this comment

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

These changes all look very similar. I wonder if there is a way to avoid the code duplication by making some kind of hook ? Looks good otherwise.

@@ -90,6 +99,7 @@ const getRepos =
}

function useSearchResultsQuery(q: string) {
const abortController = useRef<AbortController | null>(null)
Copy link
Contributor

Choose a reason for hiding this comment

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

We need to cancel the current run if the component is un-mounted (same thing in other places)

Suggested change
const abortController = useRef<AbortController | null>(null)
const abortController = useRef<AbortController | null>(null)
useEffect(() => {
// User cancelled by closing this view (navigation, other?)
return () => abortController.current?.abord('user-cancelled')
}, [])

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think i was avoiding this earlier on so that folks can run one of these and leave it running in the background while they browse and do other things. but in hindsight, that may be a bit too risky since it will make it very easy for people to leave something like this running for 20K followers or something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

agreed on the refactoring into a hook recommendation. I'm adding a ticket for that and don't wanna bite that off in this PR. let me get this out and will handle the refactoring in a future, separate PR.

@arcalinea arcalinea temporarily deployed to list-to-workspace - ozone-staging PR #220 November 18, 2024 15:25 — with Render Destroyed
@foysalit foysalit merged commit 2f5c256 into main Nov 18, 2024
3 checks passed
@matthieusieben matthieusieben deleted the list-to-workspace branch November 18, 2024 16:19
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.

3 participants