-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
Add support for changing hook order #4186
Add support for changing hook order #4186
Conversation
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.
Got a bunch of JS refactoring suggestions and other points.
src/octoprint/plugin/core.py
Outdated
@@ -1676,6 +1677,13 @@ def _activate_plugin(self, name, plugin): | |||
) | |||
continue | |||
|
|||
if not order: | |||
order = 1000 |
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.
Should be a constant, e.g. DEFAULT_ORDER
src/octoprint/plugin/core.py
Outdated
@@ -1719,6 +1727,9 @@ def _deactivate_plugin(self, name, plugin): | |||
) | |||
continue | |||
|
|||
if not order: | |||
order = 1000 |
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.
Constant
src/octoprint/plugin/core.py
Outdated
@@ -2167,11 +2178,12 @@ def sort_func(impl): | |||
impl[0], sorting_context | |||
) | |||
) | |||
sorting_value = None | |||
sorting_value = 1000 |
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.
Constant
src/octoprint/plugin/core.py
Outdated
sorting_value = None | ||
sorting_value = 1000 | ||
else: | ||
sorting_value = 1000 |
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.
Constant
for hook in data["hooks"]: | ||
# TODO: Force really needed? | ||
self._settings.global_set_int( | ||
["plugins", hook["id"], "_hook_order_overrides", hook["hook"]], |
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.
Sanity check that id
, hook
and value
are actually set on hook
.
for i in range(len(self._plugin_manager._plugin_hooks[hook])): | ||
if self._plugin_manager._plugin_hooks[hook][i][1] == plugin: | ||
self._plugin_manager._plugin_hooks[hook][i] = ( | ||
value, | ||
plugin, | ||
self._plugin_manager._plugin_hooks[hook], | ||
) | ||
return |
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.
This really feels like it should be added to the core plugin manager class instead, as it heavily interacts with internal data structures
for hook_name, hooks in self._plugin_manager._plugin_hooks.items(): | ||
order = dict(name=hook_name, hooks=[]) | ||
for order_current, plugin_id, _hook in hooks: | ||
plugin_name = self._plugin_manager.plugins[plugin_id].name | ||
|
||
_, order_original = self._plugin_manager._get_callback_and_order( | ||
self._plugin_manager.plugins[plugin_id].hooks[hook_name] | ||
) | ||
|
||
order["hooks"].append( | ||
dict( | ||
id=plugin_id, | ||
name=plugin_name, | ||
order_current=order_current, | ||
order_original=order_original, | ||
) | ||
) | ||
result.append(order) |
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.
This should prolly also be moved into the core plugin manager itself.
.fail(function () { | ||
self.requestError(true); | ||
deferred.reject(); | ||
}) | ||
.done(function (data) { | ||
self.requestError(false); | ||
self.fromHookOrderResponse(data.hook_order); | ||
deferred.resolveWith(data); | ||
}); |
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.
Really just for reasons of consistency: Swap order, first the success, then the failure case.
for (i = 0; i < data.length; i++) { | ||
for (ii = 0; ii < data[i]["hooks"].length; ii++) { | ||
data[i]["hooks"][ii]["orderStaged"] = false; | ||
data[i]["hooks"][ii]["orderTemp"] = 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.
_.each(data, function(entry) {
if (!entry || !entry.hooks) return;
_.each(entry.hooks, function(hook) {
hook["orderStaged"] = false;
hook["orderTemp"] = false;
}
}
for (var k = 0; k < self.hookOrder().length; k++) { | ||
var hookGroup = self.hookOrder()[k]["name"](); | ||
|
||
for (var kk = 0; kk < self.hookOrder()[k]["hooks"]().length; kk++) { | ||
var hook = self.hookOrder()[k]["hooks"]()[kk]; | ||
if (hook["orderStaged"]()) { | ||
changes.push({ | ||
hook: hookGroup, | ||
id: hook["id"](), | ||
value: hook["orderStaged"]() | ||
}); | ||
} | ||
} | ||
} |
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.
_.each(self.hookOrder(), function (entry) {
var hookGroup = entry.name();
_.each(entry.hooks(), function (hook) {
if (hook.orderStaged()) {
changes.push({
hook: hookGroup,
id: hook.id(),
value: hook.orderStaged()
});
});
});
});
I wonder if this could do with a short sentence at the top explaining what it is for. For a plugin developer, it is clear as this is what we use to write the plugins. However, I suspect for many people this will be the first time they have heard of these 'hooks', and they don't have any idea what it is for. Maybe needs something that recommends leaving it as is unless advised/running into problems - this is less necessary, maybe if there's an explanation it would be enough. Don't want to fill up the UI with useless information :) |
That's actually a good point. Should it maybe even be hidden behind a config flag? |
Or - another thought - do we maybe need something like "Enable developer options" or "Enable advanced options" for the settings in general? |
Not a bad idea. IMO this would be considered an advanced option rather than dev. I could also break this out into it's own plugin instead of in Plugin Manager so that it can be disabled by default. |
Advanced kinda settings are definitely something that needs some work first... the question is, should we target 1.7.0 for this here or not? |
I think 1.7.0 makes sense. Also, do you have any input on the Further notes section of the PR? |
1.7.0 is feature frozen as of yesterday (I hope to push out a first RC tomorrow, would have been today if I didn't have a doc appointment for my shoulder right in the middle that makes it difficult to plan around), so this will have to wait until 1.8.0, too many open points still and decisions to make regarding general approach for dev side stuff. Will also give me time to take another look at the TODOs you marked up. |
@kantlivelong poke :) |
@foosel OWW MY EYES! I've been holding out for your comments on the Further Notes section. 😉 |
Sorry, that first got overlooked before my poke, and then needed some time after.
See the initial review.
I'd seriously just got with "Computed" and displaying the original order number. That should transfer what this is best.
Looking at the settings structure I think this should rather be
You mean filtering by hook type? I'd honestly just say, treat them all the same, the less magic the better.
Good question. Trying to remember when |
@kantlivelong poke ;) I'm looking into starting to wrap up 1.8.0, so unless you do a race to the finish line here, this might get delayed into 1.9.0. No harm done, just want to give you a heads-up. |
d584257
to
c77c3e0
Compare
Default hook value changed from None to 1000
c77c3e0
to
66d0f30
Compare
@foosel Thanks for the nudge. For now I think I'll just submit this without the UI portion. I've kept a copy of the UI branch at https://github.com/kantlivelong/OctoPrint/tree/hook_order_overrides_with_UI should I revisit it later or someone else want to take it on. I've also adjusted according to your feedback 😄 |
* fetch settings during platform initialization instead of in plugin core * rename from hook order to sorting order as it's also used for the sorting context of implementations * make sure settings are initialized empty in defaults
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.
Added some missing docs and slightly refactored things to better match existing stuff.
What does this PR do and why is it necessary?
Allows the user to override the hook order value for plugins. Useful in cases where one plugin hook might need to be executed before another but they have conflicting order values.
How was it tested? How can it be tested by the reviewer?
Config:
Each plugin can have an additional key called '_hook_order_overrides' which contains a subkey for each hook ID.
Example:
UI:
Settings -> Plugin Manager -> Hook Order (See screenshot)
Any background context you want to provide?
What are the relevant tickets if any?
Screenshots
Further notes
I'm sure the JS side of things can be optimized better. Pointers appreciated.
I wasn't sure the best way to display what the computed default was in the UI. I just labeled it as "Definition". Originally I called it "Original" and displayed the order number instead of the value or "Default". Thoughts?
I used
_hook_order_overrides
as the config key name but if there is something better/shorter you'd prefer let me know. Same goes for the blueprint path or anything else for the matter.There are two(2) TODO lines which maybe you can answer: