Merge lp:~jtv/maas/bug-986185-conditional-node-actions into lp:~maas-committers/maas/trunk
Status: | Merged |
---|---|
Approved by: | Jeroen T. Vermeulen |
Approved revision: | no longer in the source branch. |
Merged at revision: | 522 |
Proposed branch: | lp:~jtv/maas/bug-986185-conditional-node-actions |
Merge into: | lp:~maas-committers/maas/trunk |
Prerequisite: | lp:~jtv/maas/pre-986185-exception-responses |
Diff against target: |
496 lines (+233/-63) 5 files modified
src/maasserver/forms.py (+103/-22) src/maasserver/templates/maasserver/node_view.html (+11/-21) src/maasserver/tests/test_forms.py (+99/-10) src/maasserver/tests/test_views_nodes.py (+20/-8) src/maasserver/views/nodes.py (+0/-2) |
To merge this branch: | bzr merge lp:~jtv/maas/bug-986185-conditional-node-actions |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Julian Edwards (community) | Approve | ||
Review via email: mp+103540@code.launchpad.net |
Commit message
Turn Delete Node into a regular node action.
Description of the change
Actually I split off two preparatory branches, which are independent of one another but both needed for this one. And an MP will only take one prerequisite branch, so review may have to wait until both the pre-986185-* branches are reviewed and landed.
The Delete Node button is special in many ways that set it apart from generic, easily defined “node actions”:
- It can be visible-
- It's actually a link, not a button, even though it's dressed up to look like a button.
- It requires special treatment in the view in order to control its visibility and availability like a node action's.
- It forwards to a confirmation page on a different view.
Nevertheless, this branch turns it into a regular node action. To that end I had to shave a few yaks:
1. Inhibiting node actions.
Every node action can now provide an “inhibit” function. This function looks for a reason to disable the action, but leave it visible. It returns None if there is no reason to disable it, or an explanatory text.
As it stands, all actions' inhibitions are calculated on every use of the view. This is actually a bit wasteful: on an action POST the only action that needs to be checked for inhibitions is the one that's being exercised. (The action does a double-check, so that for instance you don't accidentally delete a node that's been acquired since you loaded its overview page.) There shouldn't normally be too many actions though.
2. Compiling actions.
The node-action form had a list of references to NODE_ACTION entries, plus a more compact version of the same information. I unify them into “compiled” actions, which are like the applicable actions but any inhibitions are stored as an extra entry.
3. Disabled buttons.
A disabled action button is still a button, but with some different styling, plus a tooltip showing what's inhibiting the action, such as “you haven't registered an SSH key yet.”
4. Redirection.
The delete-node action returns a redirect to the confirmation page. This is how an action POST can support the same workflow as the first half of the old GET/POST combination. It's probably a bit less inefficient, but if that becomes a problem, we should probably be looking at mass-deletion UIs instead of shaving milliseconds off the individual operation.
In one of the prep branches I introduced a new exception type, Redirect, which conveys a temporary-redirect response to the exception middleware or, in this case, a wrapper in the view that catches MAASAPIExceptions and returns their HTTP responses. (This was already documented; the prep branch puts the logic for creating the response in the exception itself so that it's easily reusable.)
My final branch in this series will apply the new infrastructure to the Start Node button, so that you won't be able to acquire and start a node unless you have an SSH key registered to be installed on the node.
Jeroen
Thank you for this, it's quite a lot nicer! Just a few comments, and one thing that is a needs-fixing, but not your fault, you just get the straw that broke the reviewer's back I'm afraid. See below ...
-----
The DELETE_ACTION looks really disjoint against the other inline actions now, is there any more refactoring we can do with those so the NODE_ACTIONS stuff looks nicer?
26 + if node.owner is not None: has_perm( action[ 'permission' ], self.node)
27 + return "You cannot delete this node because it's in use."
28 + else:
29 + return None
...
135 + if action is None:
136 + return False
137 + else:
138 + return self.user.
You don't need the "else:" on these functions.
176 + def find_action(self, action_name): buttons:
177 + """Find the compiled action of the given name, or return None."""
178 + for action in self.action_
179 + if action['display'] == action_name:
180 + return action
181 + return None
Mostly thinking out loud here, but I wonder if we can turn action_buttons into a dict so you don't need to iterate here. Whenever I see code doing this it just makes me think it's using the wrong data types.
And here's the need-fixing thing: I remember raising this with rvb before and I'd forgotten about it, but these actions in the dicts appearing as strings is terrible, they really need to be enumerated values. Can you please see if you can sort it out in this branch since you're adding a new action? And damn, I wish we had a proper enum type :/