This is an advanced Codelab. It covers the following concepts:
How to handle data structures.
- Types:
List
,Structure
,Dictionary
. - A combination of these types.
How to use a dynamic template.
How to use table widgets.
- Use UX widgets.
- Construct different tables: A read-only table and a selectable table.
- Use tables: Select something in a table and set the input or read the output.
How to build an Atlas signal display.
- Construct a table or combo-box with multiple selections of Atlas products..
- Create a table with all the fields.
- Single-select fields to get values. Then, don't allow a duplicate selection.
How to use a scenario to test the tool.
How to test the Codelab.
In previous codelabs, we worked with some basic types: string
and number
. Data structure is how we expand the descriptive power of these basic types in order to build and organize data.
Depending on the type of data, and the data to be used, there are many types with different benefits and costs. The benefits are out of scope for this simple primer. This exercise covers the patterns of data sets and recommends a data structure that you can use for your workflows.
This type of data structure organizes data of the same kind in a sequence. The following are examples:
List
of songs on a CD:["1st song", "2nd song", "3rd song"]
List
of students in a class:["abe", "becky", "connie", "dustin"]
List
of multiple lists:[["cd1:1st song","2nd song","3rd song"], ["cd2:1st song","2nd song", "3rd song"], ["cd3:1st song", "2nd song", "3rd song"]]
Examples of functions related to lists
Size
()
: This function determines the number of items in a list.ListAppend
()
: This function adds items to a list.ListAppendIf
()
: This function adds items to a list if some condition istrue
.Contains
()
: This function finds a single item from a list.ContainsAny
()
: This function finds one of many items from a list.
Build a list of songs from CDs
Objective: Build "list1" and use functions to build a list of lists.
Task: Create an action node, InitList
, and use the following storage directives:
cdSongs = ["1st song","2nd song","3rd song"]
listOfCds = []
listOfLists = ListAppend(arg: listOfLists, value: cdSongs)
listOfLists = ListAppend(arg: listOfLists, value: cdSongs)
listOfLists = ListAppend(arg: listOfLists, value: cdSongs)
numOfCds = Size(arg: listOfCds)
The action node created looks like the following list:
Use a key value widget to display a list
Objective: Build "list1," "list2," and "list3," and use functions to build a list of lists.
Task: Create a page node, DisplayList
, and use the following form field:
information display: key-value
Label : I have ${numOfCds} cds in my collection.
Cd 1 = listOfCds[0]
Cd 2 = listOfCds[1]
Cd 3 = listOfCds[2]
The following is a Sample solution workflow:
Structure
is a type of data structure. In this type, the collection of data describes one kind of a thing by the use of basic types in order to build a more complex type. The data used doesn't have to all be of the same type.
The structure has a field name and data for the field. The field name is case-sensitive, must be unique within the structure, and have no spaces or special characters.
Objective: Create a song structure.
All songs have a title, a list of artists (whether without an artist or with many artists), a publish date, and a length in seconds. You can also mix things up with multiple types, like string
, list
, date
, and number
.
{ Title: "song", Artists: ["artist 1", "artist 2"], PublishData: 2018-01-01, Length: 450 }
A dictionary
data structure is like a real dictionary. It's used to look up unique names and to ensure that they have the correct meaning attached to them. You can use a dictionary
data structure to map a unique name (a field) to a list of strings.
For example, a teacher has three class periods and a list of students. You can use a list of lists to organize the classroom information, as follows:
{ Period1: ["student 1", "student 2", "student 3"], Period2: ["student 1", "student 2", "student 3"], Period4: ["student 1", "student 2", "student 3"]}
The advantage of the Dictionary
data structure is the ease of field data manipulation. SetField
and ClearField
are powerful functions to use with this data structure.
The following are example functions related to the Dictionary
data structure:
HasField
():
Checks if a field is in the dictionary.FieldList
():
Returns a list of fields.Map
()
Used to iterate through a list of fields.SetField
()
-ClearField
()
-
Build a dictionary of cd songs
Objective: Build dictOfCds
, and use functions to build a dictionary of cds.
Task: Create action node, InitDictionary
, with the following storage directives:
dictOfCds = {}
dictOfCds = SetField(dictionary: dictOfCds, field: "Cd1", overwrite: true, value: cdSongs)
dictOfCds = SetField(dictionary: dictOfCds, field: "Cd2", overwrite: true, value: cdSongs)
dictOfCds = SetField(dictionary: dictOfCds, field: "Cd3", overwrite: true, value: cdSongs)
numOfCds = Size(arg: FieldList(dictionary: dictOfCds))
The following action node is displayed:
Objective: Build "list1", "list2", "list3", and use functions to build a list of lists.
Task: Create page node, DisplayDict
, and use the following form field:
information display: key-value
Label: I have ${numOfCds} cds in my collection.
Cd 1 = Map(key: "Cd1", map: dictOfCds)
Cd 2 = Map(key: "Cd2", map: dictOfCds)
Cd 3 = Map(key: "Cd3", map: dictOfCds)
The following page node is displayed:
You can put these data structures, List
, Structures
, and Dictionary
, together and nest them in different ways to represent very complex, real-life things. A CD songlist. A library shelf full of CDs. You can pick and choose from these data structures to to display or manipulate data in different ways.
The Support Automation team can create new help functions and structures for you. The following are categories of other data structures that we support:
- Money:
FormatMoney
- Date and Time:
TimestampToString()
,ToMicros()
,ToNanos()
. - IP address:
UnpackIPAddress()
The following is a summary list:
list {
struct {
display_text: string
selected: bool
value: string
}
}
The following example shows the summary list used for UX widgets:
[{display_text: "summary one", selected: false, value: "val_1"},
{display_text: "summary two", selected: false, value: "val_2"},
{display_text: "summary three", selected: false, value: "val_3"}]
BuildDisplayOptions
()
is a useful function.
The following is an example of the BuildDisplayOptions
()
function used with the summary list for UX widgets:
BuildDisplayOptions(display_strings:{val_1: "summary one", val_2: "summary two", val_3: "summary three"}, values:["val_1", "val_2", "val_3"])
The following is a read-only table list:
list {
list {
<string> or <int>
}
}
The following is an example of the BuildDisplayOptions() used with a read-only table list:
[["val 1", "val 2", "val 3", "val 4", "val 5"],
["val 6", "val 7", "val 8", "val 9", "val 10"]]
The following is a selectable table list:
list {
struct {
row_data: list {
<string> or <int>
}
selectable: bool
selected: bool
value: any
}
}
The following example shows the selectable table list used for UX widgets:
[
{row_data:["val 1", "val 2", "val 3", "val 4", "val 5"], selectable: true, selected: false, value: 0},
{row_data:["val 6", "val 7", "val 8", "val 9", "val 10"], selectable: false, selected: false, value: 1},
{row_data:["val 11", "val 12", "val 13", "val 14", "val 15"], selectable: true, selected: false, value: 2}
]
In this part of the codelab you'll use generic data to dynamically alter a Redwood snippet. You'll also learn how single- and multi-select dynamic tables work.
Dynamic template and tables step 1: basic setup
Objective: Create an action node to generate some data to use for this section.
- Set up the following storage directives:
Storage directive |
|
|
|
Equal to: |
|
|
|
The following action node is displayed:
In this step, you'll create a single-select table to show the options in table_Values
. You'll set a variable to show the choice made, and to make it visible on the next screen:
- Add a table to the page.
- Name it
field_1
. - Set it to Single for row selection.
- Row data = table_Values.
- Add two columns to the table (click Add Column).
- Add a storage directive on the page to store the selection made by the user.
- table_Selection
= ouput.field_1
- Set the Next step to "new page".
The following page is displayed:
Objective: Set up and show the selection in a dynamic template.
Task: In this step, you'll create a single-select table to show the options in table_Values
. You'll set a variable to show the choice made, and to show it on the next screen.
- Create a Redwood snippet with variable placeholders. Use the text below:
This is a dynamic snippet:
- Did you know your GAIA ID is: ${gaia} ?
- Because I know your GAIA ID, I can get your email: ${email}
- You choice from the previous table was: ${myvariable}
Dynamic template and tables, step 3b: add snippet to AW
Objective: Show the selection in a dynamic template.
Task: Create a static text field and add the newly-created snippet to it in one of two ways:
Method 1
Click the text field. In Redwood, you'll notice that a toolbar shows up on top. Select Insert item > Snippet.
- What you see is what you get (WYSIWYG): You'll see the preview of the snippet. You can easily edit it.
Method 2
In the text box type TEXT_SNIPPET:<id>.
- Example:
TEXT_SNIPPET:9175757
- No preview of the snippet is given.
- Has the same result as Method 1.
Dynamic template and tables, step 3c:- make it dynamic
Objective: Show the selection in a dynamic template.
Click the 3-dot menu of the static text control screen and select Manual dictionary.3c-2; Use the values in the manual dictionary to modify the snippet dynamically. The manual dictionary replaces the variables in the snippet with variables from the workflow.
Then, set the manual dictionary value to the following:
{myvariable: table_Selection, gaia: myGaia, email: myEmail}
3c-3: Set Next step field to new decision node.
Objective: Decide what's next.
Now that you've made a selection on what you want to see, let's use your selected value to decide what's next.
There are four possible outcomes (four branches):
- Branch 1 (multi-select, overflow table)
- Condition:
table_Selection == "OT"
- Goes to a new page called "OverflowTable."
- Branch 2 (multi-select, normal table)
- Condition:
table_Selection == "MS"
- Goes to a new page called "MS."
- Branch 3 (single-select table)
- Condition:
table_Selection == "ST"
- Goes to an existing page (the first page that you created).
- Branch 4 (terminate workflow-)
- Condition:
ELSE
- Workflow is completed.
Objective:
Show a multi-select overflow table in a new page. This is the outcome from Branch 1 of Step 4.
In the page for Branch 1, follow these steps:
- Create a new table.
- Name it
field_1
. - Create three columns and name them.
- Row data is called
table_Values
.
- Use the "cog" for table settings
- Set Row selection to Multiple.
- Select Overflow columns.
- Move the Overflow columns marker as you see fit.
- Add a new storage directive to store the selection(s) you made.:
- Set
table_Selection
to equaloutput.field_1.
- Set Next step to New page. The new page shows the multiple selections that you've made.
Now you'll show a multi-select table in a new page. This is the outcome for Branch 2 from Step 4. This outcome is almost identical to that from Branch 1. However, it's without the overflow and is therefore harder to read.
In the page for Branch 2, follow these steps:
- Create a new table.
- Name it
field_1
. - Create three columns and name them.
- Row data is called
table_Values
.
- Use the "cog" for table settings.
- Set Row selection to Multiple.
- Do not select Overflow columns.
- Add a new storage directive to store the selections that you made.
- Set
table_Selection
to equaloutput.field_1
.
- Set Next step to go to the new page set in Step 5.
Now that you've made selections from the multi-select table, follow these steps to use the same snippet used in Step 3 in order to show it:
- Create a static text field and add the snippet to it.
- Click the 3-dot menu of the static text control screen to select Manual dictionary.
- The values in the manual dictionary are used to modify the snippet dynamically. Set the manual dictionary value to the following:
{myvariable: str_table_Selection, gaia: myGaia, email: myEmail}
- Set Next step to the first "action" node of the workflow.
The following is the completed workflow for the dynamic template's behavior:
https://redwood.corp.google.com/#/composer/workflowItem/9194436
Once you create your workflow, you can test it with scenarios to add mock data. Follow these steps:
- In your workflow, click on the 3-dot menu on the right side of "workflow info," and select Scenarios.
- Define a name and description.
- Click ADD MOCKS.
- Select the node you want to use in the scenario that you're building.
- Enter the scenario mock data.
- Save the workflow.
- Click LAUNCH.
Run your workflow in Scenarios
If your workflow requires a case_id
, you have to enter a real case_id
to launch your workflow in Scenario's environment.