Actions¶
Actions are how a user changes things. They live in a top-level
actions: map, separate from data:, because sources are re-fetched all
the time (on a timer, on r, on returning to a screen) and a re-fetch
must never repeat a delete.
Each action is split in two:
- The action says what to run and what inputs it needs. It never refers to the screen, so it's reusable anywhere.
- A binding on a screen says which key, which component's row fills the inputs, and whether to ask first.
actions:
pod_delete:
description: Delete a pod
inputs:
namespace: {required: true}
name: {required: true}
run: [kubectl, delete, -n, "${inputs.namespace}", pod, "${inputs.name}"]
message: "deleted ${inputs.name}"
tui:
screens:
pods:
layout: {component: pods_table}
actions:
- key: D
action: pod_delete
from: pods_table
bind:
namespace: ${selection.Namespace}
name: ${selection.Name}
confirm: "Delete ${selection.Name}?"
Every field is in Reference → Actions.
The action menu¶
a opens a menu of every action the screen has. An action that can't
run right now (because several rows are marked and it isn't multi, or
because it's already running on this row) is shown with the reason.
key: enterfires straight from the screen. A double click does too.- Any other
key:is a shortcut inside the menu. - No
key:at all is fine: the action is in the menu.
Kinds¶
| Kind | Runs | Success by default |
|---|---|---|
exec (default) |
run:, an argv, with no shell unless you write [sh, -c, …] |
exit code 0 |
http |
a request to url: |
status below 400 |
push |
opens another screen | — |
success: overrides the verdict for tools and APIs that report oddly,
for example code < 400 or code == 409 for an API that answers "already
running" with 409. message: and error_message: set the summary; for
JSON APIs, error_message: ${body.message} shows the API's own reason.
Inputs and forms¶
Inputs are typed slots. The binding's bind: fills what it can from the
focused row; anything left over is asked for in a form generated from the
input declarations: type: bool is a toggle, options: a select, and
anything else a text field.
actions:
scale:
run: [kubectl, scale, "deploy/${inputs.name}", "--replicas=${inputs.replicas}"]
inputs:
name: {required: true}
replicas: {type: int, default: "3"}
Bound with only name from the row, this asks for replicas, starting at
3.
Where results go¶
Every run reports to the output console (o): its output streams in as
it happens, the summary shows in the statusbar, and a badge counts unread
results and turns red after a failure. Nothing pops up a blocking error.
Actions don't refresh views. A view that should reflect a change polls
(refresh:), and r refetches on demand.
Several rows at once¶
With multi: true, an action runs once per marked row, each run tracked,
logged and cancellable on its own. Without it, the action is disabled
while several rows are marked rather than picking one.
exclusive: (on by default for http) refuses a second run against a row
that's already being worked on.
Claim the rows you act on¶
On a component with activity:,
a row only spins once a poll reports it busy. A claim: makes the rows an
action targets spin as soon as it starts:
actions:
restart:
run: [kubectl, rollout, restart, "deploy/${inputs.name}", --wait]
inputs: {name: {required: true}}
claim: Restarting # spins until the command returns
sync:
type: http
url: ${env.ARGOCD_URL}/api/v1/applications/${inputs.app}/sync
inputs: {app: {required: true}}
claim: {label: Running, until: status} # the API answers 202; the poll takes over
A failed run stops its rows at once, and fan-out claims each row on its own. See Reference → Claims.
Interactive commands¶
interactive: true on a binding hands the terminal to the command
(vim, ssh, kubectl exec -it) and returns to the TUI when it exits.
Drill down with push¶
A push action opens another screen. The focused row of from: is
available there as ${selection…}, and bind: fills the destination's
source parameters:
actions:
open_pod: {push: pod}
tui:
screens:
pods:
layout: {component: pods_table}
actions:
- key: enter
action: open_pod
from: pods_table
bind: {namespace: "${selection.Namespace}", name: "${selection.Name}"}
pod:
title: ${selection.Name}
layout: {component: pod_detail}
From the command line¶
wrangl can list actions and show exactly what one would run, without a
terminal UI. There's deliberately no way to run one from wrangl: the
safety gates (confirm, exclusivity, the form) are part of the TUI.
wrangl --list-actions ops.yaml
wrangl --describe-action ops.yaml pod_delete --param namespace=default --param name=web-0