-
-
Notifications
You must be signed in to change notification settings - Fork 514
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
Extend expressions to action options #2345
Comments
I think it would make more sense for the action to be skipped. Maybe
As of #2251 we handle this for feedbacks for basic variable parsing, it should be possible to extend to expressions safely. I started playing with this almost a year back in #2032, and have a very long note with my thoughts https://github.com/orgs/bitfocus/projects/2?query=is%3Aopen+sort%3Aupdated-desc&pane=issue&itemId=19678623. The TLDR is that the main question I have is: how do we store that the user has switched an input field to expression mode? The module owns the |
I would leave it to the module dev to decide what to do. E.g. the
So far I don't see a big problem with storing it in the database as extra props in options. Until now nobody can use expressions for options, so no upgrade script will take care of them if they exist. If a module starts using expressions but at the same time uses outdated update scripts, which may brake the expressions, I would call this a bug in the module. At the moment I can not think of how a module should want to manipulate the expression itself in an upgrade script, I guess it should just stay like it is. But you know, crazy guys have crazy ideas. Taking over from you nice draft (sorry I didn't find that, I was searching issues only)
Yes, if the module wants to do something if its usage is changed, we have to call unsubscribe/subscribe every time a option changes, no matter if it was a user input or a new expression result. But maybe it would help to do a finer differenciation between action added/removed and some option change. BTW: I'll update the first post along with the discussion |
I'm happy with that.
Are you suggesting the options looks like:
or
I think that doing it as an object would be better, as it gives us scope to add additional info about the expression to it. (eg a debounce time). It does make it more breaking for modules, which is where I started wondering about hiding this from the modules. I'm not too opposed to either, but its something I want to make sure is defined well as once it is done it will be in the module-api until we want another break potentially every module change.
I thought about trying to make it clever like this, as it is easy to do for number fields. but if a text field has a value of
I am thinking that a module shouldnt be able to manipulate an expression. Those would have been defined (most likely, exception being presets) by the user, and it wont be able to make any potentially needed changes to them without understanding what the user has written and how.
This is where my proposed I don't think we can do anything better because subscribe is intended to let modules only load data when it is needed. For example, in the x32 module it lets it only load the current mute state of a channel when it is needed by an action (for toggle) or a feedback. But for the value field (which will also be an expression), the module can leave
I dont think I follow this, are you saying that the value of these expressions will be shown in the ui and we can avoid doing that?
I think this is unavoidable for some expressions. But I would hope that the ones used in id fields would hopefully not be updating too frequently and be causing problems. Perhaps later on a debounce could be added, to be able to rate limit them. |
I'd vote for the flat version like
simply because this wouldn't be a breaking change for update scripts. Is there anything else about the expression which should be stored on a per option basis? Different debounce times per expression only makes sense if the user can also change the debounce time per expression.
Oh maybe I was not clear enough. If an expression should be available to the user in the database there always have to be three properties. Let's look at a textinput option definition:
Database
That is a plain string With the possibility to use an expression, but at the action creation the expression is not active
Database
The user switched to the expression and made it "1 + 2" evaluated to the number 3 resulting in the string "3" With the possibility to use an expression and at the action creation the expression is active
Database
The user switched to the value input and made it "1 + 2" resulting in the string "1 + 2" The value or result of the expression doesn't need to be stored, it is calulated at runtime.
So the module can optionally preset expressions at action creation exactly like the default value does for the regular input. And then it is the same syntax in the preset definition.
Yeah, got you now. So this could be helpful to non expression options as well.
No, the opposite. The UI should show only the expression and maybe the current value it evaluates to when having focus. And we have to calculate at the backend on any updates, not only when the action is run. |
Something else to consider here for the module side, is that perhaps we could change how the actions and feedbacks So instead of being a plain js object of the values, it could be something like: class CallbackOptions {
public getRaw(fieldName: string): any
public getString(fieldName: string): string // Or should this be `getPlainString`?
// For expressions:
public getNumberExpression(fieldName: string): Promise<number> // Or should this be `getNumber`?
// For variables:
public getAndParse(fieldName: string): Promise<string>
// This isn't all the methods, just an example of how some of this could look.
} Inside these functions we could do some data validation, so if To do this, we could add some additional action and feedback types which use this new structure, and these new types could be required when wanting to be able to use expressions. This class would help simplify things for users (especially typescript users), as then we will provide any wrappers for interpreting the values. And this will help us with tracking what variables are referenced by each action/feedback. Feedbacks today have to use the I don't know how upgrade scripts would work with this, maybe they would similarly have a class, but perhaps a different class that has different operations? Or maybe they would be left with the raw options object? |
@Julusian it looks like a small side effect is that, like the |
Is there a timeline for this functionality to be implemented in a build? It seems there are multiple modules that would benefit from this ability. |
If I may, I like the idea of callbacks, but it is possible to use some more complex typing to just provide the same object Companion was before, with full types (see here for a quick experiment). The callbacks should be an escape hatch when the module dev wants the raw values (for some weird reason). Companion should provide a final value to the module, not something they need to process. Broadly speaking. I would like to suggest that - by default - Companion should provide the final parsed result of the expression to the action, with an escape hatch (i.e. If, on the other hand, the field takes text input (i.e. My general point is, Expressions (and Variables) support should not be up to the module developer, it creates additional burden for the developer (needless checks and calls), and needless confusion and complexity for the end user. This feature needs to be seamless and pervasive to be effective and truly useful. P.S. Thanks to @thedist for helping me work out some of the idea here. |
@chabad360 yes, the idea of the implementaion is to make this a non breaking thing for modules with an opt-out. So every module can benefit from expressions without the module dev having to update the code. There will be additional features for the module to have more control. |
With the latest discussion about graphics generation and button styling in mind, I think this feature needs more priority. The toggle button besides the input would only switch what you see but would not have an impact on the result. My question is if we should store the state of this button in the database and should sync it between clients or should it be local to to a client? And if it is local what should we present initially? |
Whatever we do here should be consistent with how the togglable value/expression fields are in #3299.
I'm not sure about this. I think this will be more confusing than helpful. This isn't what we do elsewhere (which could be changed), but I don't see the value in having this split view of only seeing one of the components of the value. Why not just add
I like the approach of having a toggle next to the field to swap the behaviour of the field, and for that I am storing each field as I will once again advocate for storing each thing as an object, either way upgrade scripts will need to be aware of this, and I think that doing it as an object makes it easier for both us and them.
I don't exactly disagree with this; It would be great to make these things seamless for module devs, but I am not sure we can safely tack this on without breaking all kinds of things. Regarding my lifecycle concerns, the current flow is to at startup/when edited tell the module about each action, module-base will run upgrade scripts if needed, and call subscribe/unsubscribe as needed. So it would be trivial to auto-parse expressions when executing, but upgrade and subscribe use the same object, so I am not sure it will be easy to change one without the other (unless this requires an update to module-base) While this task is explicitly about actions, should we also consider feedbacks? The current approach for feedbacks is companion tells the module about every feedback and its properties, and the module-base code inside the module process handles the rechecking of feedbacks when the module says it needs to, or if a variable parsed in the feedback changes. If we want companion to be the one parsing expressions like is proposed here for actions, that will work, but the api used by module-base uses the same data input for starting this feedback execution and for running upgrade scripts on. I feel like I should make a diagram of this action/feedback flow/lifecycle, to make this easier to reason about/visualise.. |
Is this a feature relevant to companion itself, and not a module?
Is there an existing issue for this?
Describe the feature
Button text can be entered either as text (with inline variable support) or as an expression with numerous calculations and functions available. For the modules on the other hand there is the option to allow users to enter variables in textinput options and then parse the variables in the text.
The goal of this feature suggestion is to extend the expressions functionality to all action options.
Aspects:
expressionEnabled: boolean
to store if the expression or the original input is usedexpression: string
to preset the expression itselfaffectsSubscription
. Calls to subsribe/unsubscribe would only be made if the option changes and this property is not set to falsePossibilities tbd:
Usecases
Using variables or custom variables in actions and at the same time retaining the convenience of input elements like dropdown menu for manual selection.
The text was updated successfully, but these errors were encountered: