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

Rewrite the frontend #1856

Draft
wants to merge 29 commits into
base: main
Choose a base branch
from
Draft

Rewrite the frontend #1856

wants to merge 29 commits into from

Conversation

yuvipanda
Copy link
Collaborator

@yuvipanda yuvipanda commented May 29, 2024

/* If this file gets over 200 lines of code long (not counting docs / comments), start using a framework

This was the first line I wrote when I started writing the existing frontend, and of course that line is still there.

This PR cleans up and rewrites the entire frontend, to 'start using a framework'. There's no functional change to the UI itself, so it should be treated as a pure upgrade / refactor.

Demo

Main page

Screen.Recording.2024-05-15.at.6.03.12.PM.mov

Loading page

Screen.Recording.2024-05-23.at.8.21.36.AM.mov

Functional Status

The following functional pieces need to be completed:

  • Landing page link generator
  • Loading page
  • Actually launching servers correctly
  • Progress bars for launching
  • Stream logs
  • Favicon switching to indicate progress
  • About page
  • Extra scripts at the bottom (for google analytics / similar)
  • nbviewer in loading page
  • Help text in the main page
  • Banner on top
  • Donation button on top
  • Badge generator for markdown + rst
  • view raw logs
  • social cards
  • error page
  • fix copy button icon
  • Faithfully replicate layout
  • Fix markdown and rST icons

Technology changes

  • Upgrades to Bootstrap 5, latest version. Nicely matches JupyterHub upgrade in version 5.
  • Use react
  • Use JSDoc type annotations rather than typescript. It feels to me this gives me a good balance between the positives of optional type checking without the extra community investment needed for full typescript. This PR does switch the compiler we use from babel to tsc, but type checking is not enforced. We may choose to do so later, but not now.
  • Use react-router for URL parsing. This makes the BinderHub UI a SPA, which may be split into its own package separately in the future if so desired.
  • Move the _config endpoint to a refactored /api/repoproviders. This is with an eye on allowing us to implement Awesome bar/landing page redesign #844 eventually, as well as being able to implement the correct frontend bits in other users of the binderhub API (like https://github.com/yuvipanda/jupyterhub-fancy-profiles)
  • Deprecate direct google analytics functionality, where we embedded GA code into our source. Instead, extra_footer_scripts can continue to be used - that's what we use for matomo.

Functionality changes

  • Progress bar is now also shown in the loading page.
  • Learning from experience with nbgitpuller, the link generator now prefers outputting only urlpath - both when the user enters a file to open or a URL to open. This prevents the issue we had when we tried to change the default app that was going to open from classic notebook to lab, and broke a lot of people's stuff. By only outputting urlpath, URLs will always have this information encoded in them. The older filepath and labpath are still accepted as input, because Cool URIs don't break
  • Slightly better validation for the link generator, but most of this should be instead implemented as part of Awesome bar/landing page redesign #844

Maintenance changes

One primary goal here is to make the frontend safer to change, so it's less fragile and brittle.

  • Add some frontend tests. This should be much easier now thanks to all the componentization.
  • Provide thorough jsdoc inline documentation for everything
  • Refactor whatever is in binderhub-client package to make sure it only contains api-client related functionality - all UI stuff should be in a separate package.
  • Unify the current 'split' between the repo's root js/ and the binderhub/static/js sources of JS files. Pick up best practices from other Jupyterish projects for what to do here.

Timeline

My hope is to slowly but consistently work on this, and get it fully complete before end of June. I have also asked for some frontend review help from @batpad (either directly or via someone else), as he has significant experience in this kinda frontend work (even though he is less experienced in the JupyterHub community itself).

Fixes #774

@yuvipanda
Copy link
Collaborator Author

I've added functionality for the top banner here, and poked around to make sure that the existing banner can display well. It needs to be redone to use bootstrap 5 utility classes, but here it is:

        <div class="container-fluid position-relative" >
            <div>
                Thanks to <a href="https://www.ovh.com/">OVH</a>, <a href="https://notebooks.gesis.org">GESIS Notebooks</a> and <a href="https://curvenote.com">Curvenote</a> for supporting us! 🎉
                <br />
                mybinder.org has updated the base image to Ubuntu 22.04! See the <a href="https://repo2docker.readthedocs.io/en/latest/howto/breaking_changes.html">upgrade guide</a> for details.
            </div>

            <div class="top-0 end-0 position-absolute">
                <a class="btn" style="width:fit-content;height:fit-content;padding:10px;background-color:#e66581;color:white;font-weight:bold;"
                onmouseover="this.style.backgroundColor='#d15b75'" onmouseout="this.style.backgroundColor='#e66581'"
                href="https://numfocus.salsalabs.org/donate-to-binder" target="_blank">
                    🤍 Donate to mybinder.org!
                </a>
            </div>
        </div>

This works well!

@batpad
Copy link

batpad commented Jul 11, 2024

Have asked @oliverroick to do a review here since his React eyes are much, much sharper than mine.

Copy link

@oliverroick oliverroick left a comment

Choose a reason for hiding this comment

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

From what I can tell, this looks pretty solid. I found two occasions where you probably don't need a useEffect hook and the launch logic could be improved, I think, although I don't have the full context to make a better suggestion.

binderhub/static/js/components/LinkGenerator.jsx Outdated Show resolved Hide resolved
binderhub/static/js/components/LinkGenerator.jsx Outdated Show resolved Hide resolved
Comment on lines +28 to +31
useEffect(() => {
// Start launching after the DOM has fully loaded
setTimeout(() => setIsLaunching(true), 1);
}, []);

Choose a reason for hiding this comment

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

This looks a bit flaky. Is there a specific element you're waiting for in the DOM tree? If so how is it created?

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 think I was trying to trigger this useEffect (https://github.com/jupyterhub/binderhub/pull/1856/files#diff-17ed39387f14113cf305cbfd7cc95014fc635d5988acbe542676dd87695c967cR185) and couldn't figure out how else to do it :( In general I think I was trying to trigger 'actions' in one component based on events in a different component, and without using reducers i think i'm hackily using these 'is' booleans to do so

@yuvipanda
Copy link
Collaborator Author

Getting closer and closer!

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.

Long term planning for the Frontend
3 participants