lib/runbox/scenario/ui_action.ex

defmodule Runbox.Scenario.UIAction do
  @moduledoc """
  Definition of action to be fired from UI.

  In scenario list of `Runbox.Scenario.UIAction`s is defined and stored in asset
  map entity. When action is fired from UI, scenario receives `Runbox.Scenario.UserAction`.
  """

  alias Runbox.Scenario.UserAction
  import Runbox.Utils.Enum, only: [map_while_ok: 2]

  @typedoc """
  UI action definition.

  Properties `topic`, `type` and `details` are serialized to JWT token and used for
  routing of fired action. Property `topic` is name of raw topic where fired actions
  are pushed, property `type` is type to be used in `Runbox.Message` as `type` and
  property `details` is stored in resulting message `body` as `details` property.
  Properties `name` and `description` are only metadata for UI.
  """
  @type t :: %__MODULE__{
          topic: String.t(),
          type: String.t(),
          details: map,
          name: String.t(),
          description: String.t()
        }
  defstruct [:topic, :type, :details, :name, :description]

  @doc """
  Converts list of UI actions to actions property.

  Map in resulting list contains two properties:
    * `action` - action (`topic`, `type`, `details`) encoded to JWT.
    * `meta` - metadata (`name`, `description`) to be used in UI.

  Resulting list of maps should be stored to some entity in asset map.
  """
  @spec actions([t]) :: {:ok, [map]} | {:error, Joken.error_reason()}
  def actions(ui_actions) when is_list(ui_actions) do
    map_while_ok(ui_actions, &encode/1)
  end

  defp encode(action) do
    with {:ok, token} <- UserAction.pack(action.topic, action.type, action.details) do
      {:ok, %{action: token, meta: %{name: action.name, description: action.description}}}
    end
  end
end