flowthings.io Track GUI documentation

Overview

We've created a GUI to make Tracks a little bit easier to create. Tracks can be a bit complex to create, especially at first. This allows you to create a Track quickly and easily.

Track GUI

The GUI, as you can see above, allows you to create a Track without having to edit very much javascript directly. The GUI editor will create the javascript for you. (You can look at it if you want, but it's kinda ugly, because procedurally generated code is always ugly.)

And, it even has its own documentation built into it. If you click on the "i" in the bottom panel, you'll get information about that element:

Track GUI Documentation

This documentation will go over all of the various elements of the Track GUI and tell you how to string them together. We've also put up a tutorial for this, and you may want to go there as well.

Getting Started

Even this, I'm sure, may seem a little intimidating. Let's take a step back and we'll talk about the idea behind this GUI. It's very simple.

In fact, I'm sure you've seen something almost exactly like it before, except you've probably called it a flowcharts.

Flowchart

In a flowchart, you have steps and you have arrows linking those steps together.

In the example given above, you have the first step: your lamp doesn't work. Then you have an arrow to your next step: you should check if it is plugged in.

Our Track GUI is very similar to a flowchart. It asks the question of what you should do when a Drop comes into the source Flow. We create the first step for you: we give you a source component. Then you connect it to new components, which you choose from a list of components on the left hand side of the screen.

Components Menu

When you click and drag these components down to the screen, they become like the steps in a flowchart. The only difference is that we call them "nodes."

Nodes

Node

A node is like a step in a flowchart. It contains some logic, so that the Track knows what to do on that step, and it contains inputs and outputs. In the GUI you can move the nodes around by clicking and dragging with your mouse.

Ports

The inputs and outputs are called ports. A port on the left hand side is an in port or an input port and the port on the right hand side is an out port or an output port. Some nodes don't have any ports, some only have one, most have two or more. It depends on the kind of node.

Wires

Ports get connected together by wires. To connect two ports together on the GUI, just click on the port and drag, the wire will come out.

Wire

Each port must have a wire connecting it to another port. An input port can only be connected to an output port, and an output port can only be connected to an input port.

Routes

Routes are a bit more of an abstract idea. They are the overall route that data will travel as it goes through the Track.

Components

There are nine different types of nodes that you can use to build a Track.

Source

The Source component is the simplest. Every Track starts with a source component.

Source

When a Drop is created in a Flow, the Track is set off. The Drop enters the Track. The logic in the Track routes it somewhere else, either to another Flow, maybe to many other Flows, maybe to no other Flows. The source component is how that Drop comes into the Track. You can see the properties of the source component (or any node) by clicking on it, the bottom panel will show the properties of the node.

Source With Properties

Source has two properties that important, Var and Path.

Path is the path to the Flow that this Track is coming from. If you just leave it the default, it'll be the Flow that you created the Track on. Most of the time, you'll want to leave it the default. However, you can change it to another Flow.

Var is what you call the data in the Drop that comes in. By default, this is just called "drop." Usually, again, you'll want to keep this at the default. For the rest of the Flow, if you need to reference the Drop that came in itself, you'll call it by using the Var you named in the Source component.

These properties are required. If you don't have them (or you don't have them in the proper form), the Track won't save.

Label is the final property. It is not required, because it doesn't do anything to the Track itself. Every node has a label property. It's something we've added to help you keep better track of your code.

Source With Label

It seems odd with just one node, but it can make it a lot easier to keep track of what's going on if you have 5, 10 or even more nodes.

Aside: Required Properties

I mentioned that,if you mess up and fill in a required property wrong, it won't save. Maybe, you're worried about losing work or that, in a large project, being unable to find your error.

I can understand your fear, almost every component has required properties. We tried to make it as hard as possible to make this mistake. This documentation will go through all of them, but you can easily click on the little i to learn more about any of them.

Even better, if they're required and they're not filled in (or, if they're filled in wrong), the name of the property will show up red.

Source Invalid Example

So, even if you don't wanna read any more of the docs, and even if you won't read the little i tab, you can usually kinda trial and error it to get a valid property. (The Track may not do what you think it does, but it will be valid.)

And, it's very easy to find missing required properties, ones that you forgot to fill in, even in very complex Tracks.

Debugger Location

If you look at the right side of the bottom panel, you'll see the debugger symbol. If you click on that, it'll show you the validation failures for all of the nodes in the Track.

Debugger Open

the top node will be the currently focused node, and it will tell you all of the validation failures for that node. You can click on another node in the debugger, and the Track GUI will focus on that one. So, you can go through and correct the bugs one by one.

Config

The config component is probably the simplest of the bunch.

Config

It doesn't have any ports. All that it does is set up a variable that will be accessible from every node, which is exactly how a configuration variable ought to behave.

The Var is similar to what it was in source. It is the name of the configuration variable. So, from every node in the Track, that configuration variable will be accessible by calling the name you give it in Var. Unless you have more the one config node, which you might, it's probably easiest (and most comprehensible) to leave it as config.

Value value is the value of the configuration variable. It can be anything that's a legal javascript variable: an Array, an Object, a String, a Number and so on.

Both Var and Value are required.

Split

The split does just that, it takes in one wire as input and has the ability to output anywhere from one to five wires.

Splits

It has the ability to make more routes to more destinations in the Track GUI by splitting the data along a few different lines.

Additionally, the split does not have to use all of its output ports. It must use only one of them.

A split has ports as a required property, however the Track GUI makes it impossible to put in the wrong number, or no number at all.

Condition

Condition will check whether a condition is met. If it is, the route will continue being followed. If it is not, the route will stop.

Condition

The condition is a required property of condition. You just write the condition in simple javascript. Any statement that can be evaluated as true or false in javascript can be evaluated as a condition in the Track GUI. And, our Track GUI is smart enough to know if you wrote a proper condition or not, so don't worry.

However, it's not quite smart enough to know if the Track itself is being executed properly, so you need to be careful when writing the condition, especially because of the deeply nested structure of the JSON that makes up a Drop. Take the image above as an example.

Let's imagine that the Drop is very simple:

drop = {
  creationDate: 1423089829534,
  flowId: "f54d29f3a0cf2ec848ead3141",
  id: "d54d2a0a50cf2ec848ead331b",
  path: "/greg/demoFlow",
  elems: {
    name: {
      type: 'String',
      value: 'Greg'
    }
  }
}

I have to be sure that name exists, because I would get a nasty error if did not exist:

drop.elems.name.value === 'Greg'
--> Uncaught TypeError: Cannot read property 'value' of undefined

(Our system doesn't output an error in exactly that way, because the API is doing a lot of processing behind the scenes, but advanced users can get some of these errors by using our testing endpoint).

Since almost all of the user defined values are defined in the drop.elems object, and because you can create Drops without the hard type structure we give it internally, it can be confusing at first to write Tracks and to ensure that you're referencing the correct element in the Drop object, especially if you created drop.elems without the type/value structure. But, after you work with them for a little bit, it will be pretty easy to remember.

Switch

A switch is a split in combination with a condition.

Switch

If it meets the condition, it will go out the corresponding output port, otherwise it will go out the blue output port.

Switch Example

Drops that are named greg, in this example, will go to Destination 2, Drops that aren't will go to destination 1.

Switches can have more than one condition, as you can see.

A Switch With Many Conditions

It would work like a normal conditional statement.

if(condition1) {
  //do something
} else if (condition2) {
  //do something else
} else if (condition3) {
  //do yet another thing
} else {
  //do the last thing
}

It follows the same rules as the normal condition: write your condition as a javascript statement that will evaluate to either true or false.

If you have conditions in your switch (you don't have to, in which case the route will just pass through it and nothing will happen) they will be required properties.

Javascript

The Javascript element allows you to write plain javascript that will be evaluated within the Track.

Javascript

js, which is the javascript function you'll write, is a required property. We'll check for you if it's proper javascript. However, like with condition, we won't check if it actually does anything within the scope of the Track. You'll have to do that.

Var is optional. If you want to set the output of the javascript function to a variable, so that it may be referenced later, you set it to var, otherwise it will be run and only the side effects will have mattered to the Track. Both of these are perfectly viable options--the example above shows a javascript function that's just side effects

Unless you're using Flow.js to write the js, which you can, you're probably just referencing elements that already exist within the Track.

These functions can get very complicated, so I am not going to give you a full premier here, instead I invite you to read the other documentation on Tracks and on Flow.js, and that should give you a better idea of what this component does.

Aside: The Scope

Here's the example Track from the very top of this documentation article again, but with destination selected instead of source.

track scope

You'll notice, on the bottom left, there's a section titled scope.

scope

Here, it refers to the various variables you have access to from the selected node.

If you know Javascript (or really any other language) scope should be a concept that's familiar to you.

We put it there as a quick reference, so that you'll know what variables you can use from any given node in the Track. It's especially useful in destination, where you have to select a variable, and in the Javascript sections. If you click on any of the variables, it'll focus the Track GUI on the node where it came from, for quick reference.

The reason that we have the config component is precisely because we wanted the config to be available at every scope automatically. While you can easily do the same thing with other nodes, we wanted to make it as easy as possible.

Scope is a very important concept in Javascript. Almost any reference on Javascript will cover the concept. If you want a good place to start, I suggest checking out this Stack Overflow Thread., or going to any one of the vast number of Javascript references on the web.

Http

Http makes a call to an outside service.

http

Var is a required field, it's the variable that will hold the fetched within the Track.

Url is also a required field, it's where you're getting that data from.

If you're posting to an outside service, you'll probably want to have a javascript call before this, so that you can assemble the package that you want to post.

If you're getting something from an outside service, you'll probably want to have a javascript call after this, so that you can parse the data that you've gotten from the outside service.

Since we don't have a Track repl, you'll have to know the structure of the data that you'll get before you can parse it, so I suggest you look at the documentation for the external api that you're using. They can help you understand the structure you'll get back and how to parse it.

After you get or post something, you may also want to have a condition, that navigates the Track on one route, if the get/post succeeded and in another route if it failed. You may also want to have a Javascript call, so that you can write to a Drop whether you've succeeded or failed.

If you want to make a query on the flowthings platform, I suggest using query, rather than http.

Query

A query makes a query to the flowthings platform to get a specific Flow or Drop, or to find a Flow or Drop, using our general query methods.

These are covered in detail elsewhere in our documentation, so I won't go over it here. I'll just tell you the required properties for each of the various functions, because they are different.

To get a Flow you need the flow id:

Get Flow

There aren't any required properties to find a Flow:

Find Flow

The flow id and the drop id are required to get a Drop:

Get Drop

To find a Drop you need the flow id:

Find Drop

Destination

Destination is where you want the data to be written. It's required that you tell it what Data you want it to write, by specifying the Source Var.

And, the path to the Flow you want it written to is also required. You need to make sure that you're returning a Drop that is a proper Drop, if it's not, it won't be written. To learn more about the proper structure of a Drop, you can consult our documentation on drops.

Aside: Dynamic Behavior

Lots of the covered properties have the potential to be dynamic. For instance, Flow paths can be dynamic--you can do string interpolation on them.

/greg/example_flow/${ interpolatedVariable }

A path in the Destination is a "Template String."

Template String

Anything that is a template string can do string interpolation, such as the filter and Drop ID in queries and the URL in HTTP request.

It can be very useful, for example, if you were using a Track to monitor sales, which were all contained in one Flow, you could use string interpolation to route the sales to the Flow of the specific customer who bought something--or to the Flow of the sales clerk who sold something, you could do that based on the data that was contained in the Drop, or from, data that was grabbed from an external api.

However, it also makes Tracks a little more fragile and likely to break, if you're not positive you know what you're doing. So, there's a tradeoff you have to be sure you're on the winning side of.