-
-
Notifications
You must be signed in to change notification settings - Fork 309
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
💥✨Adjusted State Handling to prevent leaving active Conversational Components #609
💥✨Adjusted State Handling to prevent leaving active Conversational Components #609
Conversation
Hey @stammbach, first of all thanks for the PR. It points out a bug in the existing components we had created for the upcoming launch. Generally speaking, especially for components, the state stuff shouldn't be hardcoded. In your case, the component's state is hardcoded as the root state, which is not always the case. Here's an example handler: {
// root level of the project's handler.
ComponentOne: {
START() {
},
ComponentTwo: {
// nested components are possible
START() {
/**
* in this case the state would be set to `ComponentTwo.TestState`,
* which would throw an error.
* The correct path would've been `ComponentOne.ComponentTwo.TestState`
*/
this.toStateIntent('TestState', 'TestIntent');
},
TestState: {
TestIntent() {
}
}
}
}
} Because of that, the correct way to route around inside a component should be: this.toStateIntent(`${this.getState()}.TestState`, 'TestIntent'); Thanks for bringing that up otherwise I probably wouldn't have found the bug. I'd say it's not necessary for Now in the case of // active component: ComponentTwo
// current state: ComponentOne.ComponentTwo.TestState
this.toStatelessIntent('HelloWorldIntent');
// new state: ComponentOne.ComponentTwo |
Hey @KaanKC, Also, the {
MyComponent: {
START() {},
FirstState: {
START() {},
Confirmation: {
Yes() {},
No() {},
}
},
SecondState: {
START() {},
Confirmation: {
Yes() {},
No() {},
}
}
},
} So if I want to go from |
…nt with root state checks
I think I've come up with a pretty good solution. I've added the nevermind (removed) I've modified the hello world skill example with some nested components and did some testing. I could publish it if helps with your own testing. |
Yeah, I see where the issue is. I mean technically that's something you could solve yourself inside the component but maybe providing a helper is the better solution.
Could you explain your solution in a little bit more detail, please? I feel like we could solve this without making changes to the existing routing functions. I'd say we should simply add a function returning the full path to the currently active component's root state, which you can then use to call the routing methods. So in your example, it would look like this: // inside the `FirstState.Confirmation` state and you want to route to `SecondState`:
this.followUpState(`${this.getActiveComponentsRootStatePath()}.SecondState`); Maybe with a different name for the function since it's pretty long. |
There is no change with With my changes applied, toStateIntent inside a component (which is the root) just adds the provided state: toStateIntent with a component name inside throws an JovoError because you should not be able to use a component name as state: toStateIntent from any state starts at the root so I can easily get back to the start of the app/active component: toStateIntent inside a nested component will then use the active component as root there are no changes to the component usage which means wherever I think this is much more seamless and easier to remember. It will always start from the root. So inside my app it always start from the "top" of my app. For a component it always starts at the "top" of the component. Always relying on string literals are not very user friendly, also because I did not expect it to leave my component in the first place. |
I've published my test app, hope this helps with understanding what's going on. @KaanKC |
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.
Thanks for the explanation as well as the example app. That made things easier to grasp. Now that I understand it, I really like the idea. Thanks for the PR!
I've reviewed your changes and added some comments on the changes I would make. Happy to discuss anything you disagree on 👍
Removed internalToStateIntent to streamline the codebase Added triggerStateValidation property flag Moved state validation into a dedicated method
@KaanKC I did some refinement to the codebase, I kept two old discussions unresolved because of naming-reasons. Waiting for your feedback on that. Otherwise everything should be fine now. |
Fixed by resetting the triggerStateValidation flag before returning
* Checks if the given state contains the name of a initialized component. | ||
* @throws {JovoError} | ||
*/ | ||
Jovo.prototype.checkStateForInitializedComponentName = function (state: string | undefined): void { |
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.
How about adding checkStateForInitializedComponentName
to the Handler class as a private method?
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.
Moved it into the Handler class similar to the handle* methods, hope that's what you meant. Otherwise I'm not sure how to do "private" methods, I haven't had many visits to the TS-Camp yet.
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.
It was in the right place. Can you put it back into the Jovo class? :)
Sorry, my mistake.
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.
Moved it back to the Jovo class. Hope everything is alright then. Really looking forward to a release with these changes :)
Moved checkStateForInitializedComponentName() inside the Handler class
Proposed changes
Added "active component" checks to
toStateIntent
,toStatelessIntent
&followUpState
to prevent leaving the conversational component handler when using those "state" related methods.Types of changes
Not sure if it can really be called a breaking change because component are still in development
Checklist
I don't think so, because from a user standpoint I assumed to stay inside my component when using states.
All existing test are running fine for me