-
Notifications
You must be signed in to change notification settings - Fork 1
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
Base stepper PR #689
Base stepper PR #689
Conversation
Rather than the stepper template
Wow! Somehow this just works out and results in a clean merge
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, Nice job! Whew, what a beast! ;p I am starting to kindoff get it. It seems like it will be quite powerful for different apps in the future!
For my review, I had a look through everything you altered and did some minor testing. It looks like everything is working as intended, therefore, I did not really go into the minutia of how stuff works (Like SessionCheck.make_stepper_item()
...) but had a pretty good look and tried to understand the design as best I could. In general I do find it a bit complicated, but I think going over these points would improve the whole thing quite a bit!
- TaskMixin (or somewhere) still needs a StepperContextMixin. Otherwise TaskCreate and stuff cause an error. (minor)
- A clearer separation of classes that are meant to be inhereted and classes that are meant to be instantiated. Maybe these can live in different files? Because I find it a bit messy if they are all in checkers.py. Maybe just move stuff like "Base" checkers and stepper items to the helpers file. Maybe have comments throughout this file to seperate different types of Base classes ... And group different types together.
- Also Docstrings for anything intended as a baseclass would be very nice!
- Lastly, I have a bit of an issue with the Layout class. I find it a bit unclear when the Stepper does things and when the Layout does things and I feel like these could be one big Stepper class? Maybe it would be to much, but now they are also very intertwined, which is indeed a bit spaghetti-ish.
See my other comments for minor things I found.
</a> | ||
{% if url.children %} | ||
{% counter depth create 1 %} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like this is not doing anything?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
proposals/utils/stepper_helpers.py
Outdated
classes.append( | ||
"disabled", | ||
) | ||
return self._concat_css_classes( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might as well do the join here imho
proposals/utils/checkers.py
Outdated
|
||
class ProposalTypeChecker( | ||
Checker, | ||
BaseStepperComponent, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can´t this just inherit from Checker?
@@ -53,8 +54,12 @@ def get_back_url(self): | |||
return reverse(next_url, args=(pk,)) | |||
|
|||
def get_study(self): | |||
# Um.... what? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Haha Dunno. Let's get rid and have this mixin get the StudyURLMixin as well.
|
||
|
||
####################### | ||
# CRUD actions on Study | ||
####################### | ||
class StudyUpdate(AllowErrorsOnBackbuttonMixin, UpdateView): | ||
class StudyUpdate( | ||
StudyMixin, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, thanks to this handy mixin, we can get rid of the context["proposal"] = self.object.proposal
's in these views
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean doing context["proposal"] = self.get_proposal()
or moving the setting of the proposal context variable into StudyMixin?
?
Or something else?
@@ -23,12 +23,17 @@ | |||
) | |||
from ..models import Study, Documents | |||
from ..utils import check_has_adults, check_necessity_required, get_study_progress | |||
from ..mixins import StudyMixin |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is there no StepperContextMixin needed here? I'm confused ...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because StudyMixin
inherits from StepperContextMixin
, which in turn gets imported in studies/mixins.py
tasks/views/session_views.py
Outdated
@@ -90,8 +100,17 @@ def get_back_url(self): | |||
def get_study(self): | |||
return self.object | |||
|
|||
def get_proposal( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Get rid and mix in StudyMixin :)
proposals/utils/checkers.py
Outdated
|
||
class BaseStepperComponent: | ||
|
||
def __init__(self, stepper, parent=None): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just make this stuff part of the Checker and get rid of BaseStepperComponent?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I like BaseStepperComponent
to keep track of what is shared between items and checkers for now.
proposals/utils/checkers.py
Outdated
|
||
|
||
class TrajectoriesChecker( | ||
Checker, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Couldn´t you just use a ModelFormChecker? And get rid of TrajectoriesItem?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yes, that's better. Would be needed for checking errors in the future, too. Don't know why I chose not to
) | ||
return [] | ||
|
||
def make_stepper_item( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we bury this somewhere deep? xp
Alright thanks for the valuable feedback! I'm going to go through the smaller stuff first, then consider the Layout class and some of the other class hierarchies, and then document everything after. |
Okay, I think I've addressed everything. Ready for another review!
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, some really good improvement! Nice ideas and good catches. I do have some more comments.
- I am having a strange problem where clicking around in the stepper, in a new proposal or older proposal, keeps bringing me to an old proposal ... A few pk's back. Somewhere along the route, the stepper is receiving the wrong proposal object, and redirecting to it. I think this has something to do with ProposalMixin. When I get to the WMOForm and further in the form, the problem doesn´t occur anymore for me.
- I am not a huge fan of proposal type hint and suggest we get rid of it. It seems like one more place to keep track of this. I would suggest the following:
- During construction on major/4, the stepper would not appear until after you filled in the first form. I did not mind this design as it gives you kind off a zen start. Maybe we can bring this back? This would then, maybe also eliminate the need for the proposal_type_hint, as we could then just examine the proposal, and provide the correct layout based on that.
We can of course discuss this proposed solution :) See you tomorrow and enjoy the rest of your birthday.
proposals/utils/stepper.py
Outdated
The meat and potatoes of the stepper. Returns a list of top-level | ||
StepperItems to be rendered in the template. | ||
""" | ||
layout = getattr(self, "layout", False) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does it not make sense to add layout as a required argument in the stepper's init?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think so, because in almost all cases the Stepper can determine its type (and thereby layout) all by itself. The createviews are the only exception I can imagine. So if the layout was an argument it definitely should not be required.
Second, the concept of a "layout" is completely internal to the stepper implementation. I don't think every View that instantiates a stepper should need to know what a layout is and when to choose which one. The createviews know what type of proposal they're creating, because they already have to, and that should be good enough.
I think this is important because there may not exist a 1:1 mapping between proposal types and layouts. A practice proposal might use the same layout as a regular proposal, but require a different checker flow because it asks for a practice reason. Because a checker can do both of those things with just the proposal type, it makes sense to me to put that in a ProposalTypeChecker
which then also determines the layout.
Adding to the above, although it isn't necessarily relevant to your comment, is that I think that the state of the stepper object should only be modified by Checkers. Once an object is complicated enough to warrant this kind of crazy depth-first search operation with Checkers, I want to respect that and not also change object state in various object methods.
Otherwise, I can imagine myself stepping through the checkers for ages trying to debug something, only to find that it was in fact that one thing I decided to put in a Stepper method instead.
|
||
|
||
class renderable: | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this living here :)
|
||
class StepperItem( | ||
renderable, | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea to make this renderable! Streamlines the operation a lot.
proposals/utils/stepper.py
Outdated
continue | ||
# Remaining empty slots are replaced by placeholders | ||
placeholder = PlaceholderItem( | ||
self.stepper, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this should be self? This caused an attribute error for me.
|
||
def __init__(self, *args, **kwargs): | ||
if not self.form_class: | ||
raise ImproperlyConfigured("form_class must be defined") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You forgot to import ImproperlyConfigured
I was a little hasty pushing the last fixes.
But I think everything is fixed now. Thanks for finding the above.
I think this was caused by #4b8b130 and is now fixed, but please double check if it's still happening.
Although I posted a lengthy motivation above about why it currently is the way it is, I think removing the stepper from the createviews altogether is a totally cool idea that would save us some complexity, including the type hint. The reason I haven't done this is that it would be extra work and debugging right now (just before leaving for the UK), whereas the current implementation at least works. And if it turns out there's something we hadn't thought about with the alternate proposal types that does require some kind of proposal type hint, well at least it's already there. Feel free to not include the stepper in the createviews if that saves you some time, should you decide to work on the alternate proposal flows. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice that you found the fix! It looks good for now, I´d say :) Nice work!
Alright, this is ready for review. I don't consider everything done but I want to move on to other things and allow the rest of the team to continue development with a working stepper.
It's a bit of a beast with some rough edges. I encourage asking for docstrings, comments, and clarification during review.
Things that still need doing:
ModelForm
view have the instantiated form availableProposalSubmit
Thankfully, these are all smaller issues that are very doable by others now that the framework is there.