Skip to content

Instantly share code, notes, and snippets.

@couhajjou
Last active January 10, 2024 00:22
Show Gist options
  • Save couhajjou/abe2c01ea24d5d48db52ec84c0eed987 to your computer and use it in GitHub Desktop.
Save couhajjou/abe2c01ea24d5d48db52ec84c0eed987 to your computer and use it in GitHub Desktop.
A specification for Pyro Actions

Pyro Actions - Specs Proposal 0.0.1

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"

Previous art summary: Odoo

Actions in Odoo

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:

Window Action:

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.

Report Action:

Defines the generation and presentation of reports. Associated with actions that produce printable documents or reports.

Server Action:

Represents a server-side operation or workflow. Typically used for more complex business logic and automation.

Client Action:

Defines actions that occur on the client-side, often written in JavaScript. Used for dynamic and responsive user interactions without server requests.

URL Action:

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.

Views is Odoo

Form View:

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.

Tree View:

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.

Search View:

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.

Calendar View:

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.

Graph View:

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.

Pivot View:

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.

Introduction

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:

Parameters

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 interpreted
  • name: short user-readable description of the action, may be displayed in the client's interface

Optional parameters

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)

View Actions

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 for
  • views: 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 no view_name is provided, then Pyro should fetch the default view of the specified type for the requested resource
  • record_id (optional): if the default view is form, 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). Use main instead of current to clear the breadcrumbs. Defaults to current.
  • context (optional): additional context data to pass to the views
  • filter (optional): filter to implicitly add to all view search queries
  • limit (optional): the number of records to display in lists by default. Defaults to 80 in the web client
  • search_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

URL Actions (:url_action)

Allow opening a URL (website/web page). Can be customized via two fields:

  • url: the address to open when activating the action
  • target (default= new): the available values are:
    • new: opens the URL in a new window/page
    • self: 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.

Api Actions (:api_action)

Allow triggering a call to a method defined in an Ash API

  • api: the API we are calling
  • resource: 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

Evaluation context

A number of keys are available in the evaluation context of or surrounding server actions:

  • resource: resource linked to the action via resource_id
  • record/records: record/recordset on which the action is triggered, can be void.
  • env: Phoenix Environment
  • datetime, dateutil, time, timezone: corresponding Python modules
  • log: log(message, level='info'): logging function to record debug information in the logging table
  • Warning: constructor for the Warning exception

Report Actions (:report_action)

Triggers the printing of a report.

  • name (mandatory): used as the filename if print_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 about
  • report_type (default=qweb-pdf): either qweb-pdf for PDF reports or qweb-html for HTML
  • report_name (mandatory): the name (:term:external id) of the qweb template used to render the report
  • print_report_name: a Python expression defining the name of the report.
  • groups_id: the groups allowed to view/use the current report
  • multi: if set to True, 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 to True, 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 variable object

Client Actions (:client_action)

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 to
  • params (optional): a dictionary of additional data to send to the client, alongside the client action tag
  • target (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). Use main instead of current to clear the breadcrumbs. Defaults to current.

TODO - Chak:

  • Add Example

Cron Actions (:cron_action)

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 action
  • interval_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 called
  • code: 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
@frankdugan3
Copy link

frankdugan3 commented Jan 9, 2024

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:

ui_actions do
  ui_action do
    type :view_action
    resource MyApp.Resources.User
    views do
      form [:update, :create]
      tree [:read]
    end
  end
end

That would be enough to load the relevant DSL.

@couhajjou
Copy link
Author

couhajjou commented Jan 9, 2024

Actions don't define views. The spec is only for actions

I can write up a 'Pyro Views Specs Proposal' it will be another 4hours of work.
Last time we talked, I just wanted to do a 1 hour demo.
But I guess I am pulled in the pyro+ash blackhole. Hopefully I can be fast because it's a mainly a steal from Odoo.

@zachdaniel
Copy link

To me, this seems pretty far afield of what pyro cares about. I'm not sure it really has any bearing on it. What you're talking about is a DSL for building an admin interface. Pyro is declarative web components w/ ash adapters. It's possible that AshAdmin would leverage pyro, but not likely.

Some notes:

  1. While I now have a better idea of what you're getting at, I'd have to see a bigger picture implementation as well. What would the surrounding implementation look like? Where is this DSL defined? How do we get from action definitions to an admin UI?
  2. Action is a very overloaded term here, and ui_action. It seems like a lot of different things packed into a single ui_action builder.
  3. Some things in here don't really track in this context. Server actions would all be contained in resource actions, and "surrounding context" is a sort of complicated concept here (and is talking about python? It seems like quite a bit of copy-pasta remains from your original source?)
  4. Cron actions, for example, would have nothing to do with an admin interface, those would all be defined in a resource or elsewhere in the application.

Overall, I can see some of what you're getting at here, and the plan for AshAdmin is to go in a similar direction (admin UI defined in a separate dedicated DSL fit for purpose), I don't really envision it the way it is laid out here, and I think if you're serious about the ideas put forth here your best bet is to start building a prototype, and use that to clarify the proposal.

@couhajjou
Copy link
Author

couhajjou commented Jan 9, 2024

View Action --> View -> Api --> Resource --> Action

I guess I have to draw diagram of this architecture. And show all action types in it.

@frankdugan3
Copy link

I think we have some substantial problems with vocabulary overloading here. I would suggest that you use different terms for your DSL concepts than the core Ash concepts. For example, Ash heavily uses the "Action" concept. It would be a lot clearer to not use the term "Action" for any of your DSL, unless it's pointing to an Ash Action. It's very hard to distinguish what's going on with all the term overloading, "Action" just being one example of that confusion.

@couhajjou
Copy link
Author

couhajjou commented Jan 9, 2024

So it's Action as in Interaction Design. User action.
If Zach chose Methods (as in a OOP context) or Verbs (as in a REST context), then Actions would be natural for UI. And we would not have this naming discussion. But I am sure we will have another one ;)

Naming is the hardest thing in software. So it's important to have a central authority and that's Ash Core team.
I care about semantics to get my idea across, and Odoo calls them Action, and academically it respects previous art.

So it's the name I used to express the meaning.

Ultimately we can call them something else, and I'll rather let Zach come up with a congruent name.

I hope that I clarified the semantics and I defer naming to Zach.

@couhajjou
Copy link
Author

couhajjou commented Jan 9, 2024

I am addressing Zach concerns that were posted above

zach> While I now have a better idea of what you're getting at, I'd have to see a bigger picture implementation as well. What would the surrounding implementation look like? Where is this DSL defined? How do we get from action definitions to an admin UI?

zach> 1. Action is a very overloaded term here, and ui_action. It seems like a lot of different things packed into a single ui_action builder.

me> I am going for feature coverage. This is day one for this effort. So monolith is ok for a few days.
Slicing and unpacking is necessary before release, but we have to shape this DSL monster before we can slice. Right now it's 2 big parts: ui_actions and views. You can call them Triggers and Views. or x_ and Views. (semantically if my head they are actions as in User Action, and as in Interaction Design)

zach> 1. Some things in here don't really track in this context. Server actions would all be contained in resource actions, and "surrounding context" is a sort of complicated concept here (and is talking about python? It seems like quite a bit of copy-pasta remains from your original source?)

me> "A server action is a a type of action that calls a resource action". Yeah it's sounds horrible !
Variants:

  • A server action is an action that call a resource method. (if you rename actions in resource to methods)
  • An Action Trigger is a UI Trigger that calls a resource action. (if you keep the current ash naming)

zach> Cron, for example, would have nothing to do with an admin interface, those would all be defined in a resource or elsewhere in the application.
me> We can kill this one, for now.

@zachdaniel
Copy link

I'm not going to be able to spend more time with this for a while unfortunately, so ultimately this would need to be your own project if you want to work on it in the near term. I'm happy to answer any questions about Ash that come up in that process.

@couhajjou
Copy link
Author

couhajjou commented Jan 10, 2024

Yeah, I know Zach. Thanks for you time and your support. it's been great so far and above my expectations.
So it's encouraging me to give back.

I'll strive to stay coherent and within the spirit of Ash.
I can go with triggers or ui_triggers instead of 'ui_actions' for now and rename thinks later when we merge the naming.
At least for now, we that we will not confuse people.
I will be mainly seeking support about SparkDSL from Discord.

Solo can go fast, and it's a good thing. But I am listening to whoever want to participate in this effort.

@couhajjou
Copy link
Author

new document version

  • 0.1.0: added "Previous Art Section" where I provide a summary of Odoo actions and views

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment