Disclaimer: This is heavily based on Odoo. A lot of copy-pasting of the action docs, I changed the language and some of the design to adapt it to Ach. This document was requested by Zach.
Versions:
- 0.0.0: Quick draft (4 hours of work, copy-pasting and adaptation) - @couhajjou
- 0.0.1: gpt4 corrections - @couhajjou
- 0.1.0: added "Previous Art Section"
In Odoo, an "Action" is an object that represents a user's request to perform an operation. It defines what should happen when a user triggers a button, menu item, or any other interactive element. There are several types of actions, each serving a distinct purpose:
Represents the opening of a new window in the user interface. Used for actions like opening a specific form view, tree view, or other UI components.
Defines the generation and presentation of reports. Associated with actions that produce printable documents or reports.
Represents a server-side operation or workflow. Typically used for more complex business logic and automation.
Defines actions that occur on the client-side, often written in JavaScript. Used for dynamic and responsive user interactions without server requests.
Represents actions that open a specific URL. Useful for integrating external resources or linking to external websites. Actions are linked to various elements in Odoo, such as buttons, menu items, or triggers within the system. By defining actions, developers can customize and control the behavior of the Odoo application to meet specific business requirements.
Purpose: Displays a single record with input fields for editing. Structure: Contains various field widgets (text, date, selection, etc.) arranged in a structured layout. Usage: Primary view for creating, editing, and displaying detailed information about a specific record.
Purpose: Presents a list of records in a tabular format. Structure: Displays selected fields in columns, allowing quick scanning and editing of multiple records. Usage: Ideal for managing and manipulating datasets with multiple records.
Purpose: Facilitates the search and filtering of records based on specified criteria. Structure: Provides a search bar and filters for refining data retrieval. Usage: Helps users locate specific records quickly by applying various search criteria.
Purpose: Represents records in a calendar format. Structure: Displays records chronologically, often in a monthly, weekly, or daily view. Usage: Useful for managing time-based data, such as events, appointments, or deadlines.
Purpose: Displays data in graphical formats like bar charts or line graphs. Structure: Presents a visual representation of data trends and patterns. Usage: Offers insights into numeric data, aiding in the analysis of trends and comparisons.
Purpose: Enables users to analyze and summarize data through pivot tables. Structure: Allows users to drag and drop fields for dynamic data analysis. Usage: Useful for aggregating and presenting data in a structured manner, offering flexibility in data exploration.
UI Actions (or Pyro Actions) define the behavior of the system in response to user actions: login, action button, selection of an invoice, ...
UI Actions can have a code_interface
section that creates elixir and/or JS hooks so that it can be triggered from elixir (and Iex) and/or with Phoenix.LiveView.JS.
The are 6 type of Pyro Actions:
All UI actions share two mandatory parameters:
type
: the category of the current action, determines which parameters may be used and how the action is interpretedname
: short user-readable description of the action, may be displayed in the client's interface
Aside from their two mandatory parameters, all actions also share optional parameters used to present an action in an arbitrary resource's contextual menu:
resource_contextual_menu
: specifies on which resource we can see the UI action. ex: if we set this to :customer, the UI action will show on the contextual menu of customer.contextual_menu_type
: which contextual menu the action will appear under, it can be one of::action_contextual_menu
(default): Specifies that the action will appear in the Action contextual menu of the bound resource.:report_contextual_menu
: Specifies that the action will appear in the Print contextual menu of the bound resource.
view_types
: a list of view types for which the action appears in the contextual menu, mostly "list" and / or "form". Defaults to[:list, :form]
(both list and form)
The most common action type, used to present visualizations of a resource through views
: a view action defines a set of view types (and possibly specific views) for a resource (and possibly specific record of the resource).
Its fields are:
resource
: resource to present views forviews
: a list of(view_type, view_name)
pairs. The first element of each pair is the category of the view (list, form, calendar, cards, map, ...). If noview_name
is provided, then Pyro should fetch the default view of the specified type for the requested resourcerecord_id
(optional): if the default view isform
, specifies the record to load (otherwise a new record should be created)target
(optional): whether the views should be open in the main content area (current_area
), in full-screen mode (fullscreen
) or in a dialog/popup (new
). Usemain
instead ofcurrent
to clear the breadcrumbs. Defaults tocurrent
.context
(optional): additional context data to pass to the viewsfilter
(optional): filter to implicitly add to all view search querieslimit
(optional): the number of records to display in lists by default. Defaults to 80 in the web clientsearch_view_id
(optional - chak> I will elaborate on this later)
For instance, to open customers (user
with the customer
flag set) with list and form views:
ui_actions
ui_action
type: :view_action
resource: :user
views: [tree: false, form: false]
filter: expr(:user.customer, "=", true) # chak> Zach how to do this properly?
end
end
Or to open the form view of a specific product (obtained separately) in a new dialog:
ui_actions
ui_action
type: :view_action
resource: :product
views: [tree: false, form: false]
record_id: filter(:product.name, "=", "Ash Coffee Mug")
target: :new # this will open a dialog, other options are :fullscreen and :current_area
end
end
Allow opening a URL (website/web page). Can be customized via two fields:
url
: the address to open when activating the actiontarget
(default=new
): the available values are:new
: opens the URL in a new window/pageself
: opens the URL in the current window/page (replaces the actual content)download
: redirects to a download URL
Example:
ui_actions
ui_action
type: :url_action
url: "https://ash-hq.com"
target: :self
end
end
This will replace the current content section with the Ash home page.
Allow triggering a call to a method defined in an Ash API
api
: the API we are callingresource
: resource linked to the action, the resource should be referenced in the API
# demo.ex
defmodule Kech.Demo do
use Ash.Api, extensions: [AshAdmin.Api]
resources do
resource Kech.Demo.Customer
resource Kech.Demo.Order
end
end
ui_actions
ui_action do
type: :api_action
api: :demo
resource: :customer
# ...
# ...
end
end
code
(code - chak> this is rough): Specify a piece of elixir code to execute when the action is called
ui_actions
ui_action
type: :api_action
resource: :customer
code do
# chak> this is not clear yet. it's gonna be either:
# - arbitrary elixir code
# - or some DSL for a limited type of code based on usage patterns
# chab> what variables will be available here implicitly (evaluation context, see below)?
# elixir code here
# elixir code here
end
end
A number of keys are available in the evaluation context of or surrounding server actions:
resource
: resource linked to the action viaresource_id
record
/records
: record/recordset on which the action is triggered, can be void.env
: Phoenix Environmentdatetime
,dateutil
,time
,timezone
: corresponding Python moduleslog: log(message, level='info')
: logging function to record debug information in the logging tableWarning
: constructor for theWarning
exception
Triggers the printing of a report.
name
(mandatory): used as the filename ifprint_report_name
is not specified. Otherwise, only useful as a mnemonic/description of the report when
looking for one in a list of some sort
resource
(mandatory): the resource your report will be aboutreport_type
(default=qweb-pdf): eitherqweb-pdf
for PDF reports orqweb-html
for HTMLreport_name
(mandatory): the name (:term:external id
) of the qweb template used to render the reportprint_report_name
: a Python expression defining the name of the report.groups_id
: the groups allowed to view/use the current reportmulti
: if set toTrue
, the action will not be displayed on a form view.paperformat_id
: field to the paper format you wish to use for this report (if not specified, the company format will be used)attachment_use
: if set toTrue
, the report is only generated once the first time it is requested and re-printed from the stored report afterward instead of being re-generated every time. Can be used for reports that must only be generated once (e.g., for legal reasons)attachment
: an expression that defines the name of the report; the record is accessible as the variableobject
Triggers an action implemented entirely in the client (the front end).
tag
: the client-side identifier of the action, an arbitrary string that the client should know how to react toparams
(optional): a dictionary of additional data to send to the client, alongside the client action tagtarget
(optional): whether the client action should be open in the main content area (current
), in full-screen mode (fullscreen
), or in a dialog/popup (new
). Usemain
instead ofcurrent
to clear the breadcrumbs. Defaults tocurrent
.
TODO - Chak:
- Add Example
Actions triggered automatically on a predefined frequency.
name
: Name of the automated action (Mainly used in log display)interval_number
: Number of interval_type uom between two executions of the actioninterval_type
: Unit of measure of frequency interval (minutes
,hours
,days
,weeks
,months
)numbercall
: Number of times this action has to be run. If the action is expected to run indefinitely, set to-1
.doall
: Boolean specifying whether the missed actions have to be executed in case of server restarts.resource_id
: resource on which this action will be calledcode
: Code content of the action. Can be a simple call to the resource's method:
# Code block example
nextcall
: Next planned execution date of this action (date/time format)
TODO - Chak
- Add Example
Regarding the design for
ui_actions
, it would be necessary to specify which resource action(s) to use for each of the view options, e.g:That would be enough to load the relevant DSL.