Part 4: Working with Sessions

Create a session, write data to that session, and see those changes reflected in Skylight Web.

Time Required: 30 Minutes

So far in this series of quick tutorials, you’ve learned how to create Skylight applications, control them with event scripts, and bind your cards to static application data. Application data is great for static situations, but most of the time you’ll want to work with data that is not static. Often, you’ll want users to be able read and write data associated with their unique instance of the work. This could be a service work order, the assembly of a component in a manufacturing facility, a pick walk consisting of multiple items, or any other number of other units of work organization.

Skylight uses work sessions (sessions for short) to organize these unique instances of work. A session consists of:

  • Descriptive metadata

    • Created timestamp

    • Name

    • Description

    • Developer-definable properties

    • Status (either open or closed)

  • A data store, formatted as JSON

  • A history of the events that affected the session

  • Any media that has been captured as part of the session

  • A list of participants

Sessions are incredibly powerful and you’ll be interacting with them a lot. As you build your application, you control when sessions are created, updated, and closed so you can ensure their behavior best suits your use case. You can also choose either to create sessions with logic inside your application or through the integration API so that an external system of record can manage session creation and assignment. As users interact with applications, the changes they make to a session is synced automatically. For more detailed information regarding work sessions and how they function, check out Core Concepts: Work Sessions.

As you’ll see in the next part of this getting started series, the Skylight Integration APIs allow external systems of record to modify sessions and react to their events. In this way, sessions also form the connection between your applications and integrated systems of record.

Now that you know what work sessions are, let’s see how they work!

Setup

Before we get started, let’s make sure everything is ready for you to work. Please make sure you’ve read and completed:

Creating and Modifying a Session

In the previous exercise, we used data bindings to display data representing an assembly procedure. We stored the data in the Application Data.

In this quick start, we’re going to modify the application to create a session every time you build a subassembly so we can create an audit trail.

  1. Open your Quick Start application from the previous exercise.

  2. In this example, we’re going to add the logic to create a new session when selecting the process. Select the card in your root view that has its text bound to application.data.processName and then click on the action in the On Select event's action list to edit the action.

3. With the action dialog open, click on the [<>] icon next to the script name to bring up the script editor.

4. We’re going to keep the code that is already in there, but we want to create the new session before we open that view, so add the following code to your script above the call to skylight.openView:

let newSession = await skylight.session.create({ name: skylight.application.data.processName })
await skylight.session.set(newSession.sessionId)
let newData = {
"stepStatus": {
"1": "incomplete",
"2": "incomplete",
"3": "incomplete"
}
}
await skylight.session.saveData(newData)

This code calls the Skylight scripting API to create a new session. Note that we pass in the process name as the name of the session. Once that call returns a session object, we set our client’s current session by passing the ID to a call to session.set. Finally, we initialize some data in the session by calling saveData. We could use the information in application.data to build this dynamically, but for simplicity’s sake, we’re just going to hard-code it inside this script for now as this logic will get replaced in Part 5. When you’re done, your script should look like the screenshot below. Save the script and then save your application.

5. Let’s update the session whenever someone performs a task. To keep it straightforward, we’re going to toggle a complete/incomplete state for a step when selecting the card and update the associated session data each time. Open up the stepsList view and select the card that you data bound previously. On this card, we will write the status of the given step to our session. Create an event action for On Select that includes the following code (any label will suffice, e.g. Update Status). Let’s call the script updateStepStatus:

await skylight.session.saveData({stepStatus: {[event.data.id]: "complete"}})

There’s a lot to unpack in this single line of code! Work session data is made up of atomic data patch events so you only have to write the actual data you want to add or update. It is represented as a JSON so you have complete control over the schema that you implement in your session data, just like you did your application data. Since we already populated our session data when we created it, selecting various cards is going to have the following effect:

// After tapping on the first card session data will be:
{
"stepStatus": {
"1": "complete",
"2": "incomplete",
"3": "incomplete"
}
}
// After tapping on the second:
{
"stepStatus": {
"1": "complete",
"2": "complete",
"3": "incomplete"
}
}
// And so on...

You’ll also note that we use event.data.id in our code. event.data contains the context to which the card was bound. In Part 3: Displaying Data, we set this card’s context to application.data.steps so the card will repeat for each step in the array and event.data will be the step for which the card is generated. For example, the first card’s context will be bound to the first item in the array, which is:

{
"id": "1",
"title": "Prepare Component 1"
}

As a result, we can use the id parameter of event.data in the On Select event action script to figure out which step to update. Also, you’ll note that we’re using property accessor notation here for our JSON when updating the step completion. You might wonder why we’re not structuring our work session data as an array like we did in with the application data in the last quick start. The reason has to do with the immutability of arrays in in this context. Arrays are great ways to store data that you want to read from to create lists of items through data binding, but they’re not appropriate for accessing individual data items to make updates. You could write code that would look through the array, compare ID’s and replace the element of the array but that would be inefficient and unnecessarily complicated. Using this schema and notation, we’re able to make updates to the exact element we want.

6. Launch the web client via the Preview button and run through your application. When you’re done, go back to Application Builder and click Preview again, but this time, select Session inspector. The Session Inspector is a development tool that allows you to view sessions and examine their contents for debugging purposes. You should see a single new session. When you click on it, you’ll be able to expand the data tab that displays the current state of the session data. You can also see each individual data change event that was made over time.

7. So we’ve created our session and have written some data to it, but let’s make our application a little bit more complete. First, we’ll provide a way to complete the procedure and close the session. Add a new Text card to the end of your stepsList view.

8. Select that new card and set its Text property to Complete Process.

9. Add a new event action to the Complete Process card’s On Selectevent with the following logic to close our session and navigate back to the main application view so you can start another process. We’ll use the label Complete Process and name this script completeProcess:

await skylight.session.close()
await skylight.openView({viewId: 'root'})

10. Save your application with this new action and verify that each time you start a process a new Session is created and that each time you complete it, that Session is closed. Now let’s add a little bit of UI to let our users know which steps have been completed. You can write all sorts of logic in your data binding statements to make your UI more responsive. We’re going to define an icon for each step card that defaults to a red “X” and toggles to a green checkmark when the step has been completed. Go to your stepsList view and select the card whose context is bound to application.data.steps.

11. Enable the icon by selecting the checkbox on the right side of the Icon property.

12. Now, click on the {} data binding button that appears to the left of the Icon property when you hover over it. You can define logic for each of its three sub-properties.

13. We'll set the visible property to always return true. This isn't strictly required, but it is good practice:

{{ true }}

14. Enter the following logic for the text.icon.uriproperty. This will switch between the “yes” and “no” icons depending on the value currently stored in our session:

{{ session.data.stepStatus[context.id] === 'complete' ? 'resource://ic_misc_confirm_yes_01' : 'resource://ic_misc_confirm_no_01' }}

15. Enter the following logic for the text.icon.color property. We’ll do the same type of logic for the color, but this time we’re returning strings for the color code instead of the icon resource:

{{ session.data.stepStatus[context.id] === 'complete' ? '#00DF06' : '#FF0000'}}

16. Now that we’ve added logic that changes the icon and color depending on the state of the data stored in the session, let’s enhance our data bound step card in the stepsList view to take the current state of the step into account so that we create a “toggle” interface. Update the updateStepStatus script to reflect the following, either by selecting the script through the action on the On Select event of the card, or by going to Application scripts in the File menu:

//await skylight.session.saveData({stepStatus: {[event.data.id]: 'complete'}})
const currentlyComplete = skylight.session.data.stepStatus[event.data.id] === 'complete'
await skylight.session.saveData({stepStatus: {[event.data.id]: currentlyComplete ? 'incomplete': 'complete'}})

Now test your app and verify that you can toggle the various steps of a process on and off and that your session data is updated appropriately. Note that as you change your steps' status, a history of all the changes you’ve made builds within the session. You can keep the Session Inspector open and use it to see what’s going on inside of your work sessions as you develop.

By combining application data and session data, we’ve created an application that is actually using Skylight’s built-in persistence mechanisms to create a system of record that can track the status of our assembly process over many users and executions. Often, however, the very data that defines these processes lives in an existing system of record outside of Skylight. Move on to Part 5 to learn how you can use Skylight’s Integration API to control session data and react to its changes!