View Source Runbox.Scenario.UserAction (runbox v20.0.0)

Toolbox for working with scenario user actions.

User action is action created by scenario and fired by user (usually from UI). Scenario is usually also a receiver of fired action. Assumed workflow is following:

  1. Scenario creates actions to be fired in the future and Altworx stores them.

  2. UI displays available actions.

  3. User fires selected action from UI.

  4. UI pushes the action to raw Kafka topic (defined in action) with extra data attached (usually empty).

  5. Normalizer pipeline receives the action and sends it to target scenario via a runtime topic.

Currently, user actions can be attached only to incidents. This can be done either via the user_actions field of Runbox.Scenario.OutputAction.Incident and Runbox.Scenario.OutputAction.IncidentPatch or using Toolbox.Workflow.

Normalized user actions

Fired output actions are normalized into a %Runbox.Message{} with %Runbox.Scenario.UserAction{} in its body. For example:

%Runbox.Message{
  from: "N6_rt_camera_user_actions",
  type: "close_incident",
  timestamp: 1750857766412,
  body: %Runbox.Scenario.UserAction{
    type: "close_incident",
    details: %{
      "submit_text" => "Close the incident",
      "type" => "button"
      "incident_id" => "6157565f-8c9e-3e66-a5f6-2c4d6211a9c1",
    },
    user: "joe",
    data: %{}
  },
  origin: %{offset: 2, partition: 0, topic: "camera_user_actions"}
}

Summary

Types

t()

Fired user action.

Functions

Unpacks the action and fetches access tags associated with it.

Unpacks action and makes it fired (prepared for sending to target topic).

Helper for UserAction forwarding to be used in normalizer.

Packs user action to JWT to be used (fired) later (from UI for example).

Parses string containing JSON to Runbox.Scenario.UserAction.

Types

@type t() :: %Runbox.Scenario.UserAction{
  data: any(),
  details: map(),
  type: String.t(),
  user: String.t()
}

Fired user action.

When action is fired by the user, it should be pushed to raw topic with current timestamp to be correctly reordered by Normalizer. Properties type and details should contain enough information for routing action to the target scenario. Property user is ID of user who fired the action, data contains extra information attached by environment where user fired the action (for example comment filled by the user on UI).

Functions

Link to this function

fetch_access_tags(token)

View Source
@spec fetch_access_tags(Joken.bearer_token()) ::
  {:ok, [String.t()]} | {:error, Joken.error_reason()}

Unpacks the action and fetches access tags associated with it.

Returns error if packed action (JWT) is not valid.

Link to this function

fire(packed, user, data)

View Source
@spec fire(Joken.bearer_token(), String.t(), any()) ::
  {:ok, topic :: String.t(), String.t()} | {:error, Joken.error_reason()}

Unpacks action and makes it fired (prepared for sending to target topic).

Routing properties (type, details) are propagated from packed action, user and data properties are attached to fired action. Target topic is also extracted from packed action.

Returns error if packed action (JWT) is not valid.

Link to this function

normalizer_pipeline_step(msg)

View Source
@spec normalizer_pipeline_step(Runbox.Message.t()) :: Runbox.Message.t()

Helper for UserAction forwarding to be used in normalizer.

If helper is used in normalizer pipeline configuration in config.ini like

[pipelines.some_pipeline]
definition = Runbox.Scenario.UserAction.normalizer_pipeline_step

then Runbox.Message body will contain fired Runbox.Scenario.UserAction.

Link to this function

pack(topic, type, details, opts \\ [])

View Source
@spec pack(String.t(), String.t(), map(), [{:access_tags, [String.t()]}]) ::
  {:ok, Joken.bearer_token()} | {:error, Joken.error_reason()}

Packs user action to JWT to be used (fired) later (from UI for example).

Parameter details must be a map encodable to JSON. Because details can be (and it is!) encoded/decoded to/from JSON during its life-cycle, atom keys in details are always converted to string keys in fired action's details.

details must contain "type" which is currently always "button" and submit_text which will be used as the user-facing label for the button. Other fields are up to you.

Optionally, access_tags can be given inside opts to control access to the action. A user must have all of the specified access tags to be able to fire the action. If access tags are not given, the default [] is used, which means that anyone can fire the action.

Example

UserAction.pack("camera_user_actions", "close_incident", %{
  "type" => "button",
  "submit_text" => "Close the incident",
  "incident_id" => "6157565f-8c9e-3e66-a5f6-2c4d6211a9c1"
}, access_tags: ["camera", "privileged"])
@spec parse_raw_action(String.t()) :: t()

Parses string containing JSON to Runbox.Scenario.UserAction.