Conversation
|
@GeraldIr this looks good to me! Do you mind writing up a couple sentences on what this solves and exactly what the expected behaviour here would be? And then am happy to test. It would also be nice to figure out writing a test for this - I can help with that once we have this outlined a bit. Thank you for your contribution! |
|
I've found the workflow of Build Image -> Start Image a bit cumbersome, so I was just looking for a way to simplify it down to a single press of a button. Ultimately I'd like to add an auto-start option for permalinks as well, in order to go from Click Permalink -> Running JupyterLab in a single click from anywhere without further user-input. This is a feature for the original BinderHub UI so that's what I'm trying to replicate. To be honest, I mistakenly opened the PR early, so for now I'll change this to a draft. |
|
@GeraldIr haha no worries - and yes, automatically starting the server once the image builds sounds really good to me and happy to help how I can to get this merged. For auto-starting on the Permalinks, let me open a separate ticket as well. In principle, this seems really nice - I think my only concern is if there's any security considerations to worry about - i.e. user clicks link and starts a server with a malicious image, etc. - the current way at least there is a bit of a confirmation step. Not sure how much of a concern this is as something we should worry about. Thanks again for jumping into this! |
|
I've included auto-start (build and start) from permalinks now. To trigger this, include the "autoStart":"true" in the Permalink values. I'll still need to include some tests, as well as hiding the Start button when the Build and Start Button is visible for the ImageBuilder (just confusing to have the vestigial button remain). |
|
As for the security concerns, as the standalone binderhub UI already works the same way I don't see much of an issue with this; but I am not a cybersecurity expert and usually take such concerns too lightly, so there is that 😅 |
|
I've now consolidated the Build and Start buttons from the custom image builder into a single button, as well as made it easier to create auto-starting permalinks, by including the autoStart option set to false by default when copying a permalink. |
|
@rtmiz 🙌 thank for you for this! I'll spend some time testing this tomorrow, but I will need to find some help to do a proper review as this does touch a fair bit of things. Could you add a short note, either to this PR or somewhere in the docs / code (I need to do a proper overhaul of the docs soon, so you can drop it here and I can use the text when I do the overhaul is fine) that:
I'll give this a whirl this week and let you know any feedback around usability, and then try and find someone who is able to do a proper frontend review - but in general, this is looking good to me, ty! |
|
cc @wildintellect @maxrjones - getting y'all's eyes on this: I think I might have seen you ask for something similar - would be good to get a 👍 from y'all on the general idea behind the feature and validating the usefulness would help me prioritize getting this merged. |
|
Of course, here's my rationale: I wanted to simplify the user experience down from 2 separate button clicks to 1. Previously the custom image building UI featured a "Build"-button, which built and pushed the image and then a "Start"-button, which initiated the spawning process of the previously built image. I couldn't think of a real use-case in which starting didn't follow building every time, so I merged the buttons. As for the auto-start feature, this is something we were looking for in our deployment and have now used to great success. We combined the autoStart option with multiple ?next= referrals (for login as well as invoking nbgitpuller) to cut down the workflow for users. This basically allowed us to generate URLs which are a 1-click referral to a specific environment with a specific notebook and it's been a great boon for tutorial sessions and our notebook gallery. Copied permalinks also now include a "autoStart": "false" by default, to make generating autoStart URLs easier. As for testing: Both features should be rather straightforward to test behavior on.
|
That sounds super-cool! If you have anything public that you're able to share, I'd love to get a better sense of how y'all are using this. |
|
@batpad You can find our notebook gallery here: https://eopf-sample-service.github.io/eopf-sample-notebooks/gallery/ From there select a notebook and click the Launch in JupyterHub button! You'll need to create an account though to use it, but otherwise it should be accessible. Also, there seems to still be some issues related to permalinks (values don't get updated if you opened the page via one and autoStart doesn't work yet for the build image page). I'm working on these right now. I can also share a piece of code when these issues are fixed that generates these URLs, this would also be of interest to @maxrjones for his second issue #137 |
|
To fix the issue I added a timeout when auto-starting so the form can properly load (this is a hack imo, but I don't know enough about react to fix this in a proper manner). @maxrjones Here's the code I mentioned earlier, make sure the image you are building will have nbgitpuller installed: |
|
I'd love for 2i2c to celebrate this work in a blog post. I invite @rtmiz and/or @batpad to share some quick information using this issue template. I thank my colleague @choldgraf for helping to make wins like this more visible to a wider audience. |
|
@yuvipanda The tests/linting now pass locally. |
|
@colliand I've posted the blog entry here: 2i2c-org/2i2c-org.github.io#527 |
|
Thank you @rtmiz ! |
|
@batpad No worries! |
| if (form) { | ||
| const button = form.querySelector("button[type=\"submit\"]") as HTMLButtonElement | null; | ||
| if (button) { | ||
| setTimeout(() => { |
There was a problem hiding this comment.
This seems like a neat hack indeed. Would just be curious to see if there's some-how a better way to do this, this does seem like it could get brittle and hard to debug in some edge case scenarios.
There was a problem hiding this comment.
Echoing @batpad 's concern - there are two ways of submitting the form in this file. Any reason of not using requestSubmit (https://github.com/2i2c-org/jupyterhub-fancy-profiles/pull/132/files) for this case?
|
The code looks good to me and I think we should do a bit of testing and merge this in. @hanbyul-here would you be able to help with getting this over the line:
Looking at the code and thinking about this a bit, I think we can get this in before #122 and don't need to wait. Overall, this looks fine to me - in general, we need to fix the way Permalinks work, but that depends on upstream changes in Jupyterhub, so I do think we should go ahead with this and update docs to reflect this change. |
|
|
||
| renderWithContext(<ProfileForm />); | ||
| renderWithContext( | ||
| <form> |
There was a problem hiding this comment.
Needing to wrap the <form> around the <ProfileForm> in the tests makes sense to me - since fancy-profiles gets "injected" onto a page that already contains the container <form> tag, the <ProfileForm> expects to be rendered inside an existing <form> - since that does not exist during tests, we add it this way.
This looks a little awkward, but makes sense to me. Just giving @hanbyul-here some context while reviewing - not sure if there's a way to do this that feels more elegant, but this seems okay to me.
There was a problem hiding this comment.
🤔 imo, it is ideal if the test's scope is narrowed enough that the test doesn't have to cover any unnecessary tasks. Most tests were scoped down well enough that it doesn't need additional wrapper. I understand some tests might need this wrapper now since this PR makes form submission this application's responsibility. but I still feel like we can get rid of this additional wrapper for the ones that don't need one?
I think one of the biggest change this PR introduces is the programatic form submission -
There’s something nice about letting HTML handle form submission — it keeps the application’s responsibility focused on processing and cleaning the data. This PR expands that responsibility. That’s not necessarily a bad thing, but we would at least need a test for it.
Maybe we can add an explicit test to check if form submission worked with this additional wrapper?
…false to copied permalink to make creating auto-start urls easier
…r full auto-start (login->profile-selection->notebook) configuration
|
@batpad I've rebased the changes from main and added the documentation for the feature to the existing myst pages. I've also included the code-snippet that I've posted above for nbgitpuller integration and handling login via URLs, I thought it might be a nice addition to complement this feature. |
|
@rtmiz I took the liberty of doing a merge with the latest (adds this bit to Apologies again for the long wait - if @hanbyul-here has no comments, I think we should merge this soon. Thanks again! |
hanbyul-here
left a comment
There was a problem hiding this comment.
I am still getting myself familiar with the codebase but I thought it would be better to start the conversation early rather than hang up. So please bear with me if I read anything wrong.
| if (form) { | ||
| const button = form.querySelector("button[type=\"submit\"]") as HTMLButtonElement | null; | ||
| if (button) { | ||
| setTimeout(() => { |
There was a problem hiding this comment.
Echoing @batpad 's concern - there are two ways of submitting the form in this file. Any reason of not using requestSubmit (https://github.com/2i2c-org/jupyterhub-fancy-profiles/pull/132/files) for this case?
src/ProfileForm.tsx
Outdated
| onClick={handleSubmit} | ||
| > | ||
| Start | ||
| { buildImageStart ? "Build Image and Start" : "Start" } |
There was a problem hiding this comment.
This doesn't get synced with the user's current choice - When I toggle back to one of the default options, the button still says 'Build Image and Start' (and will start the server with custom image instead of one of the default options that I selected)
If I am reading the flow correctly, there is no way to prevent a user from hitting submit multiple times while the image is building, and there is no 'check' to see if the image building is already in progress. I am concerned that this will result in multiple build triggers.
There was a problem hiding this comment.
Unsure what you mean by this not syncing with the user's current choice? This is how it looks on my end.
As for the multi-submit, you are right, there is currently nothing stopping the user from either submitting the form again or changing to a different drop-down item during the build process. I'll see to it that the form gets disabled during building.
There was a problem hiding this comment.
re:Syncing user's choice: Ah! I forgot that dev environment is different per config. My config (default config that comes with the app) has more than one profile, so user can navigate between profiles. (There is a case where ImageBuilder is not unmounted yet, while a user's current choice is not building a custom image, which leaves the text on the button unsync) Is this very unlikely configuration set up in real life?
state-unsync.mov
There was a problem hiding this comment.
Ahh, I see, I can replicate this on one of my deployments! I'll see if I can find a fix for this.
There was a problem hiding this comment.
This should be fixed with my newest changes.
src/ProfileForm.tsx
Outdated
| if (buildImageStart){ | ||
| await buildImageStart(); | ||
| } | ||
| setShouldSubmit(true); |
There was a problem hiding this comment.
I might be missing something but I can't figure out why this needs to be handled indirectly. Can we directly call form.requestSubmithere?
There was a problem hiding this comment.
Nope, you're right I've changed both this and the other occurrence to form.requestSubmit()
There was a problem hiding this comment.
I actually take this back, I didn't test it properly, using form.requestSubmit in either of these circumstances does not work for reasons unknown to me (but presumably the reason I have it in there how it is, it's been a while now).
I agree that there should be a neater way of doing all of this, but I've ended up with what works over what seems like it should work here
src/ImageBuilder.tsx
Outdated
| return () => { | ||
| setBuildImageStart(null); | ||
| }; | ||
| }, []); |
There was a problem hiding this comment.
I am guessing a lot of added useRefs are to get updated values for handleBuildStart. I wonder if we can trigger the this hook with those values that need to be updated? (moving dependencies of this hook https://github.com/2i2c-org/jupyterhub-fancy-profiles/pull/132/files#diff-fa607bb96a32d3e9d15c039c5b36fa3806089f0a0023d231194f996ec3fea311R205 to here?)
src/ProfileForm.tsx
Outdated
| const form = document.querySelector("form"); | ||
|
|
||
|
|
||
| const formIsValid = form.checkValidity(); |
There was a problem hiding this comment.
Shouldn't form validation happen before building image?
There was a problem hiding this comment.
This is before building no? It's in the extra submitTheForm Function (arguably a bad function name), but we aren't building here yet, we're just doing manual form validation.
There was a problem hiding this comment.
Isn't the flow (from https://github.com/2i2c-org/jupyterhub-fancy-profiles/pull/132/files#diff-57e82f51ce2ff82498b68631c62c2bf5723ee306d5f89d5a4728012f0ae999e4R52-R56)
buildImage if there is one => and display the form errors (submitTheForm but not blocking form submit) => Submit ? Which means that even if Repository input is not valid, it will start the buildimage (even if it errors)
This behavior is also related to this comment https://github.com/2i2c-org/jupyterhub-fancy-profiles/pull/132/files#r2632003823
There was a problem hiding this comment.
I've reworked the flow now, if you could check it out again.
|
|
||
| renderWithContext(<ProfileForm />); | ||
| renderWithContext( | ||
| <form> |
There was a problem hiding this comment.
🤔 imo, it is ideal if the test's scope is narrowed enough that the test doesn't have to cover any unnecessary tasks. Most tests were scoped down well enough that it doesn't need additional wrapper. I understand some tests might need this wrapper now since this PR makes form submission this application's responsibility. but I still feel like we can get rid of this additional wrapper for the ones that don't need one?
I think one of the biggest change this PR introduces is the programatic form submission -
There’s something nice about letting HTML handle form submission — it keeps the application’s responsibility focused on processing and cleaning the data. This PR expands that responsibility. That’s not necessarily a bad thing, but we would at least need a test for it.
Maybe we can add an explicit test to check if form submission worked with this additional wrapper?
| }, 100); | ||
|
|
||
| setProfileError(!selectedProfile ? "Select a container profile" : ""); | ||
| e.preventDefault(); |
There was a problem hiding this comment.
This line was preventing the invalid form from being submitted, but now the form can be submitted with invalid values.
There was a problem hiding this comment.
This should be fixed with my newest update.
|
I've made some more updates as per @hanbyul-here 's suggestions and I think we can probably merge this soon @batpad . Sorry for the delay from my end, with the holidays and some other work I didn't have much time for this. |


Consolidation of Build and Start buttons in the custom image building UI into one button.
Permalinks now feature a autoStart field, that when set to true will instantly initiate the spawning process of the given environment.