davestewart / javascript-state-machine

An expressive, feature-rich, event-driven JavaScript finite-state machine
http://statemachine.davestewart.io
342 stars 25 forks source link

Does this fit your JSM concept? #3

Closed StevenBlack closed 8 years ago

StevenBlack commented 8 years ago

I like what you're doing here @davestewart.

Can I solicit your comment on something?

I have parts, thousands per month, that fit into approx 30 different partType and these parttype breakdown into maybe 10 possible workflows like [ordered > received > shipped > installed] or [fabricated > shipped > installed]. The complete transit can take between days and months.

So a workflow is a state machine through which a part traverses.

EXCEPT — and this is my problem — I haven't yet found a JSM I can use as follows:

I'd like to fetch a part record from the database and, given its current state and knowing its parttype, pass it to a JSM instance that has

As you might guess, I'd like to use JSM instances to help me build a smart UI so parts can be pushed from state to state.

Most JSMs seem to assume a lifecycle of transitions, and don't seem to support the the notion of arbitrarily mutating state and then providing prior/subsequent transitions as information, in addition to raising events as transitions happen.

I hope this makes sense :smile

Any thoughts on this? Have you seen a JSM that can provide prior and subsequent states as info?

x = new MyFSM( options );
x.state = "shipped";

console.log( x.next() );  // "installed"
console.log( x.nextAll() );  // ["installed", "inspected"]
console.log( x.prior() );  // "fabricated"
console.log( x.priorAll() );  // ["planned", "approved", "fabricated"]

In practice the return values from these methods would be objects, essentially the sub-hash of the settings of MyFSM for each state.

davestewart commented 8 years ago

Hey Steven,

Thanks! It's been a lot of fun to write :D

Take a look at the TransitionMap class which is exposed as fsm.transitions:

https://github.com/davestewart/javascript-state-machine/blob/master/docs/api/transitionmap.md

It's the main logical component within StateMachine and has a bunch of methods that allow you to query state or actions for any state.

If you look at the bottom of the main plane demo, you can see I use this to get the next set of available cities:

So I'm thinking your approach would be as follows:

  1. Store your various transition configurations in a hash, and grab the correct transitions config per partType.
  2. Choose your initial state based on the stage that the order is at (retrieved from the database)
  3. In your handlers block, add a change (or other) handler and query fsm.transitions.getStatesFrom(event.target) to update your UI accordingly
  4. Instantiate the FSM with said options

Would this do what you want?

As for your question about walking the state tree, this is also something I've been thinking about, and should be possible with passing in proposed states to TransitionMap, and querying the same FSM instance. I may implement some kind of A-Star algorithm to StateHelper at some point.

For v1.1 I'm planning on introducing nested StateMachines, but to do this I'm pretty sure I'll need to change state from being a string to being a class, so any state will be a named State or a named StateMachine.

This should make it much easier to walk states there will need to be no pre-collation of states, as you'll be able to query a class' transitions directly:

state.actions[action].state.actions[action].state...

StevenBlack commented 8 years ago

Thanks Dave! This is right up my alley. Excellent!

davestewart commented 8 years ago

FYI event.target might change to event.name or event.source at some point; I know it's what's used in DOM events, but I'm not sure it's quite right for this project.

Events are going to get one last look before I release, so let me know if you have a go and update your code if you have any thoughts!

StevenBlack commented 8 years ago

I'd namespace event identifiers and sleep soundly.

davestewart commented 8 years ago

The events have Classes and types, but the target in this case is the actual action or state that has triggered the event handler.

You'll see when you run the code or debug a demo!