Action Apps
Actions allow apps to expose an autogenerated UI for simple backend actions. For use cases where an existing CLI application or API needs to be exposed as a web app, actions provide an easy solution. An app can have one or more actions defined. Each action has to be given a unique path, which does not conflict with any other route defined for the app.
Sample Action
First, define the parameters to be exposed in the form UI. Create a params.star
file with the params. For example,
param("dir", description="The directory to list files from", default="/tmp")
param("detail", type=BOOLEAN, description="Whether to show file details", default=True)
This app defines a run handler which runs ls
on the specified directory. The output text is returned.
load ("exec.in", "exec")
def run(dry_run, args):
if args.dir == "." or args.dir.startswith("./") or args.dir == ".." or args.dir.startswith("../"):
return ace.result("Validation failed", param_errors={"dir": "relative paths not supported"})
cmd_args = ["-Lla" if args.detail else "-La", args.dir]
out = exec.run("ls", cmd_args)
if out.error:
return ace.result(out.error)
return ace.result("File listing for " + args.dir, out.value)
app = ace.app("List Files",
actions=[ace.action("List Files", "/", run, description="Show the ls -a output for specified directory")],
permissions=[
ace.permission("exec.in", "run", ["ls"]),
],
)
The app, when accessed will look as shown below, with the ls
command output displayed:
Action Definition
An action is defined using the ace.action
struct. The fields in this structure are:
Property | Optional | Type | Default | Notes |
---|---|---|---|---|
name | false | string | The action name | |
path | false | string | The path to use within app path | |
run | false | function | The function to run on execution | |
suggest | true | function | none | The function to run on suggest, currently unused |
description | true | string | none | The description for the action |
The name and description are shown in the app UI. The app params are displayed in a form. BOOLEAN
types are checkboxes, others are text boxes.
When the form is submitted, the run
function is called. The params are passed as an args
argument. The response as returned by the handler is shown on the UI.
args
argument to get the values from the form. Referencing params
will give the default values for the parameters, not the actual values passed in.Action Result
The handler returns an ace.result
struct. The fields in this structure are:
Property | Optional | Type | Default | Notes |
---|---|---|---|---|
status | true | string | The action status message | |
values | true | list | [] | The actions output, list of strings or list of dicts |
report | true | string | ace.AUTO | The type of report to generate. Default is ace.AUTO , where it is selected based on response type. Other options are ace.JSON , ace.TEXT , ace.TABLE . Any other value is a custom template name. |
param_errors | true | dict | {} | The validation errors to report for each param. The key is the param name, the value is the error message |
Validating Params
The run
handler can validate the parameters. If there are errors, it can return a validation error like
if args.dir == "." or args.dir.startswith("./") or args.dir == ".." or args.dir.startswith("../"):
return ace.result("Validation failed", param_errors={"dir": "relative paths not supported"})
Errors can be reported for multiple params.
Report Types
The response values
can be a list of string or a list of dicts. The report is generated automatically by default. For list of strings, the report is a TEXT report. For list of dicts, the report can be either
- TABLE - selected if all dict values for the first row are simple types
- JSON - selected if any of the values for the first row is a complex type (like dict or list)
For TABLE report, the fields from the first row are used as columns. Extra fields in subsequent rows are ignored. For JSON report, a JSON tree representation of each row is shown. The report type can be set to specific type instead of using AUTO.
Custom Templates
If the report
type is set to any value other than ace.AUTO/TEXT/JSON/TABLE
, that is treated as a custom template to use. The template should be defined in a *.go.html
file. Either the file name can be used or a template/block name can be used. See template for details.
For styling, Clace uses DaisyUI by default, so default styles are reset. The custom template can use inline styles or it can use TailwindCSS/DaisyUI. For DaisyUI, the app has to be run in dev mode first for the style.css to be generated. See styling for details.
See dictionary code:demo for an actions example app which shows different type of reports.
Param Value Selector
For some params, it is useful to be able to provide a list of values from which the user can choose. The way this is supported is by using an options param. If param1
is a param which should show up as a selector, then define another param with the name options-param1
, of type LIST
. Set a default value for options-param1
with the values to show in the selector dropdown. For example
param("param1", description="The param1 description", default="option1")
param("options-param1", type=LIST, description="Options for param1", default=["option1", "option2"])
In the UI, options-param1
is not displayed. param1
is show with a selector, having option1
and option2
as options. See dictionary for an app which uses this.
This approach is used for flexibility, instead of directly allowing the options to be configured for the param. The options param approach has the flexibility that when an app is installed, the options can be configured for the installation. This avoids having to maintain different copies of the app code. For example:
clace app create --approve --param options-param1='["option1", "option2", "options3"]' /mycode /myapp
adds a new options3
option.