mirror of
https://github.com/YunoHost/doc.git
synced 2024-09-03 20:06:26 +02:00
add documentation on how to write config panel and actions
This commit is contained in:
parent
3117a2aa83
commit
08414c24aa
6 changed files with 482 additions and 0 deletions
BIN
images/actions_example.png
Normal file
BIN
images/actions_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 53 KiB |
BIN
images/config_panel_example.png
Normal file
BIN
images/config_panel_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 55 KiB |
BIN
images/config_panel_toml_example.png
Normal file
BIN
images/config_panel_toml_example.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 125 KiB |
144
packaging_apps_actions.md
Normal file
144
packaging_apps_actions.md
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
# Applications Actions
|
||||||
|
|
||||||
|
<div class="alert alert-warning">For now, all those features are <b>EXPERIMENTAL</b>
|
||||||
|
and aren't ready for production and are probably going to change again, if you
|
||||||
|
still decide to use them don't expect them to be stable and follow to core
|
||||||
|
development of YunoHost otherwise <b>they might randomly breaks on your apps</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Applications "actions" is a packaging feature that allow you to ship with your
|
||||||
|
application a list of "actions" executable from both the cli and the admin
|
||||||
|
interfaces.
|
||||||
|
|
||||||
|
"actions" are a list of custom commands that, optionally, has arguments (like
|
||||||
|
the installation script of an application has arguments) and once called will
|
||||||
|
called a specific selected command with those arguments. Like an "actions"
|
||||||
|
restart service with a argument "service name" could called the command
|
||||||
|
`systemctl restart $some_service` (but don't that specific action in your app,
|
||||||
|
it's just for example purpose).
|
||||||
|
|
||||||
|
Like the installation page generated from the manifest those actions can accept
|
||||||
|
a list of arguments.
|
||||||
|
|
||||||
|
Their main purpose is to expose procedures that a sysadmin would normally do on
|
||||||
|
CLI but that your application user would want to do but don't have the
|
||||||
|
knowledge to do by themselves via ssh (or are just too lazy for that).
|
||||||
|
|
||||||
|
For example those could be:
|
||||||
|
|
||||||
|
* importing data in a application
|
||||||
|
* generate a custom backup
|
||||||
|
* start a procedure like synchronising file with the file system (nextcloud for example)
|
||||||
|
* purge a local cache
|
||||||
|
* restart some services
|
||||||
|
* modify a theme
|
||||||
|
|
||||||
|
Actions looks like this in the admin interface:
|
||||||
|
|
||||||
|
![actions admin screenshot](images/actions_example.png)
|
||||||
|
|
||||||
|
## How to add actions to your application
|
||||||
|
|
||||||
|
Adding actions to your application is pretty simple as it is very similar to
|
||||||
|
writing your manifest for the application installation.
|
||||||
|
|
||||||
|
You need to write an `actions.toml` file in your application at the root level
|
||||||
|
like the `manifest.toml`/`manifest.json`.
|
||||||
|
|
||||||
|
The general pattern looks like this:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[first_action]
|
||||||
|
name = "some name"
|
||||||
|
description = "some description that will be displayed"
|
||||||
|
|
||||||
|
# can be a bash command like so:
|
||||||
|
command = "echo pouet $YNH_ACTION_FIRST_ARGUMENT"
|
||||||
|
# or a path to a script like
|
||||||
|
command = "/path/to/some/stuff --some-flag $YNH_ACTION_FIRST_ARGUMENT"
|
||||||
|
|
||||||
|
user = "root" # optional
|
||||||
|
cwd = "/" # optional, "current working directory", by default it's "/etc/yunohost/apps/the_app_id"
|
||||||
|
# also the variable "$app" is available in this variable and will be replace with the app id
|
||||||
|
# for example you can write "/var/www/$app"
|
||||||
|
accepted_return_codes = [0, 1, 2, 3] # optional otherwise only "0" will be a non enorous return code
|
||||||
|
|
||||||
|
[first_action.arguments]
|
||||||
|
# here, you put a list of arguments exactly like in manifest.toml/json
|
||||||
|
[first_action.arguments.first_argument]
|
||||||
|
type = "string"
|
||||||
|
ask = "service to restart"
|
||||||
|
example = "nginx"
|
||||||
|
|
||||||
|
... # add more arguments here if needed
|
||||||
|
# you can also have actions without arguments
|
||||||
|
|
||||||
|
[another_action]
|
||||||
|
name = "another name"
|
||||||
|
command = "systemctl restart some_service"
|
||||||
|
|
||||||
|
[another_action.arguments]
|
||||||
|
[another_action.arguments.argument_one]
|
||||||
|
type = "string"
|
||||||
|
ask = "some stuff"
|
||||||
|
example = "stuff"
|
||||||
|
|
||||||
|
... # add more arguments here if needed
|
||||||
|
# you can also have actions without arguments
|
||||||
|
```
|
||||||
|
|
||||||
|
You can have as much actions as you want and from zero to as many arguments you want.
|
||||||
|
|
||||||
|
If you prefer, you can also write your actions in json like manifest.json:
|
||||||
|
|
||||||
|
```json
|
||||||
|
[{
|
||||||
|
"id": "restart_service",
|
||||||
|
"name": "Restart service",
|
||||||
|
"command": "echo pouet $YNH_ACTION_SERVICE",
|
||||||
|
"user": "root", # optional
|
||||||
|
"cwd": "/", # optional
|
||||||
|
"accepted_return_codes": [0, 1, 2, 3], # optional
|
||||||
|
"description": {
|
||||||
|
"en": "a dummy stupid exemple or restarting a service"
|
||||||
|
},
|
||||||
|
"arguments": [
|
||||||
|
{
|
||||||
|
"name": "service",
|
||||||
|
"type": "string",
|
||||||
|
"ask": {
|
||||||
|
"en": "service to restart"
|
||||||
|
},
|
||||||
|
"example": "nginx"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
... # other action
|
||||||
|
}]
|
||||||
|
```
|
||||||
|
|
||||||
|
## How to use actions
|
||||||
|
|
||||||
|
### In the admin
|
||||||
|
|
||||||
|
<div class="alert alert-warning">For now since those features are still
|
||||||
|
experimental you won't find any direct links to the app actions on the app
|
||||||
|
page</div>
|
||||||
|
|
||||||
|
The actions are located on https://some_domain.tld/yunohost/admin/#/apps/$app_id/actions
|
||||||
|
|
||||||
|
## With the CLI
|
||||||
|
|
||||||
|
The CLI API is very similar to application installation. You have 2 commands:
|
||||||
|
|
||||||
|
* `yunohost app list $app`
|
||||||
|
* `yunohost app run $app $action_id` ("$action_id" is the this between "[]"
|
||||||
|
like "[another_action]" in the example)
|
||||||
|
|
||||||
|
`list` will obviously give you all actions for an application.
|
||||||
|
|
||||||
|
`run` will run an existing action for an application and will ask, if needed,
|
||||||
|
values for arguments. Like with `yunohost app install` you can use the `-a` and
|
||||||
|
pass arguments in the HTTP POST arguments format (like
|
||||||
|
`&path=/app&domain=domain.tld&other_value=stuff`)
|
40
packaging_apps_advanced.md
Normal file
40
packaging_apps_advanced.md
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
# Advanced features of apps packaging
|
||||||
|
|
||||||
|
<div class="alert alert-warning">For now, all those features are <b>EXPERIMENTALS</b>
|
||||||
|
and aren't ready for production and are probably going to change again, if you
|
||||||
|
still decide to use them don't expect them to be stable and follow to core
|
||||||
|
development of YunoHost otherwise <b>they might randomly breaks on your apps</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
## Actions
|
||||||
|
|
||||||
|
Actions allow you to ship a list of executables "actions" related to your
|
||||||
|
application, for example that could be:
|
||||||
|
|
||||||
|
* import data
|
||||||
|
* generate a custom backup
|
||||||
|
* start a procedure
|
||||||
|
* regenerate a local cache
|
||||||
|
|
||||||
|
[Full documentation](#/packaging_apps_actions)
|
||||||
|
|
||||||
|
Example in the admin:
|
||||||
|
|
||||||
|
![actions admin screenshot](images/actions_example.png)
|
||||||
|
|
||||||
|
## Configuration Panel
|
||||||
|
|
||||||
|
Configuration or "config_panel" allow you to offer a custom configuration panel
|
||||||
|
for your application integrated into YunoHost administration panel. This allow
|
||||||
|
you to expose whatever configuration you want for your application and this is
|
||||||
|
generally used to handle an application configuration file when this is not
|
||||||
|
possible inside the application itself.
|
||||||
|
|
||||||
|
This is generally also the place where you want to add the option to make an
|
||||||
|
application public or not.
|
||||||
|
|
||||||
|
[Full documentation](#/packaging_apps_config_panel)
|
||||||
|
|
||||||
|
Example in the admin:
|
||||||
|
|
||||||
|
![actions admin screenshot](images/config_panel_example.png)
|
298
packaging_apps_config_panel.md
Normal file
298
packaging_apps_config_panel.md
Normal file
|
@ -0,0 +1,298 @@
|
||||||
|
# Applications Configuration Panel
|
||||||
|
|
||||||
|
<div class="alert alert-warning">For now, all those features are <b>EXPERIMENTAL</b>
|
||||||
|
and aren't ready for production and are probably going to change again, if you
|
||||||
|
still decide to use them don't expect them to be stable and follow to core
|
||||||
|
development of YunoHost otherwise <b>they might randomly breaks on your apps</b>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
Configuration panel, or "config_panel", is a way for an application to ship a
|
||||||
|
custom configuration panel available in the YunoHost's admin interface for the
|
||||||
|
application. This is generally used to replace the "you need to manually edit
|
||||||
|
this configuration file (or files) in whatever format/language for this
|
||||||
|
application in cli and do all those complex commands" to "just use to
|
||||||
|
configuration panel to change the options of the application".
|
||||||
|
|
||||||
|
Yes, this is one place to add this so asked "how can I make my application from
|
||||||
|
public to private and vice versa" user request.
|
||||||
|
|
||||||
|
config_panel is probably the most complex YunoHost apps feature as you'll need
|
||||||
|
to write both a description of the panel in toml and a script that will need to
|
||||||
|
both work in a "display mode" and "handle inputs" mode. But this is still very
|
||||||
|
doable and very worth it if you need it.
|
||||||
|
|
||||||
|
Here how it looks like in the admin interface:
|
||||||
|
|
||||||
|
![actions admin screenshot](images/config_panel_example.png)
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
### Admin interface
|
||||||
|
|
||||||
|
The configuration panel for an application can be accessed with this url:
|
||||||
|
|
||||||
|
https://my_domain.tld/yunohost/admin/#/apps/$app_id/config-panel
|
||||||
|
|
||||||
|
<div class="alert alert-warning">For now since those features are still
|
||||||
|
experimental you won't find any direct links to the app actions on the app
|
||||||
|
page</div>
|
||||||
|
|
||||||
|
### CLI
|
||||||
|
|
||||||
|
For now the CLI API for the config panel is not very good at all, you can still
|
||||||
|
use it but it's really impracticable.
|
||||||
|
|
||||||
|
* `yunohost app config show-panel $app_id` will show the panel. **But for now
|
||||||
|
it's very broken and will asked question for unfilled value of the panel**.
|
||||||
|
|
||||||
|
* `yunohost app config apply` will call the script with apply and... no values
|
||||||
|
since you aren't passing them, except if you are ready to play with the `-a`
|
||||||
|
flag and pass every global value in the HTTP POST format (protip: you don't)
|
||||||
|
|
||||||
|
In conclusion: don't use the CLI for now, we need to design something better.
|
||||||
|
|
||||||
|
## How to add a config_ panel to your application
|
||||||
|
|
||||||
|
### config_panel.toml
|
||||||
|
|
||||||
|
Firs, you need to write a `config_panel.toml` (or `config_panel.json` if you
|
||||||
|
REALLY wants it but we really don't recommend it has it is very error prone and
|
||||||
|
frustrating to write by hand) that will be located at the root of you
|
||||||
|
application, next to the manifest.json/toml. It looks like this:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
version = "0.1" # version number, not used yet but important
|
||||||
|
name = "name that will be displayed on the admin"
|
||||||
|
|
||||||
|
[section_id]
|
||||||
|
name = "name of the section that will be displayed"
|
||||||
|
|
||||||
|
[section_id.sub_section_id]
|
||||||
|
name = "sub section"
|
||||||
|
|
||||||
|
# those arguments are in yunohost argument format like manifest.json
|
||||||
|
[section_id.sub_section_id.option_id]
|
||||||
|
ask = "the text displayed for the option"
|
||||||
|
type = "argument_option"
|
||||||
|
default = true
|
||||||
|
help = "A public Leed will be accessible for third party apps.<br>By turning on 'anonymous readers' in Leed configuration, you can made your feeds public."
|
||||||
|
|
||||||
|
[section_id.sub_section_id.another_option_id]
|
||||||
|
...
|
||||||
|
|
||||||
|
[section_id.another_sub_section_id]
|
||||||
|
name = "stuff"
|
||||||
|
|
||||||
|
[another_section_id]
|
||||||
|
name = "stuff"
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
And a real world example with the rendered admin:
|
||||||
|
|
||||||
|
![config_panel_toml_example](images/config_panel_toml_example.png)
|
||||||
|
|
||||||
|
As a text format:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
version = "0.1"
|
||||||
|
name = "Leed configuration panel"
|
||||||
|
|
||||||
|
[main]
|
||||||
|
name = "Leed configuration"
|
||||||
|
|
||||||
|
[main.is_public]
|
||||||
|
name = "Public access"
|
||||||
|
|
||||||
|
# those arguments are in yunohost argument format
|
||||||
|
[main.is_public.is_public]
|
||||||
|
ask = "Is it a public website ?"
|
||||||
|
type = "boolean"
|
||||||
|
default = true
|
||||||
|
help = "A public Leed will be accessible for third party apps.<br>By turning on 'anonymous readers' in Leed configuration, you can made your feeds public."
|
||||||
|
|
||||||
|
|
||||||
|
[main.overwrite_files]
|
||||||
|
name = "Overwriting config files"
|
||||||
|
|
||||||
|
[main.overwrite_files.overwrite_nginx]
|
||||||
|
ask = "Overwrite the nginx config file ?"
|
||||||
|
type = "boolean"
|
||||||
|
default = true
|
||||||
|
help = "If the file is overwritten, a backup will be created."
|
||||||
|
|
||||||
|
[main.overwrite_files.overwrite_phpfpm]
|
||||||
|
ask = "Overwrite the php-fpm config file ?"
|
||||||
|
type = "boolean"
|
||||||
|
default = true
|
||||||
|
help = "If the file is overwritten, a backup will be created."
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
### the scripts/config script
|
||||||
|
|
||||||
|
To make your configuration panel functional you need write a "config" script
|
||||||
|
that will be location in the "script" folder like the "install" script. This
|
||||||
|
script will be called at 2 different occasions:
|
||||||
|
|
||||||
|
* when the configuration panel is displayed and yunohost needs to fill the values
|
||||||
|
* when the configuration is modified by the user
|
||||||
|
|
||||||
|
Every option of the configuration panel will be send to the script
|
||||||
|
following this naming convention:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
YNH_{section_id}_{sub_section_id}_{option_id} (everything in upper case)
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, this option value:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[main]
|
||||||
|
name = "Leed configuration"
|
||||||
|
|
||||||
|
[main.is_public]
|
||||||
|
name = "Public access"
|
||||||
|
|
||||||
|
# those arguments are in yunohost argument format
|
||||||
|
[main.is_public.is_public]
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
Will be available under this name in the config script:
|
||||||
|
|
||||||
|
```
|
||||||
|
YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC
|
||||||
|
```
|
||||||
|
|
||||||
|
Also, the same "scripts/config" script is called in both situation. To differentiate
|
||||||
|
those situation the first argument passed to the config script is either "show"
|
||||||
|
or "apply".
|
||||||
|
|
||||||
|
A common pattern to handle that is to write your script following this pattern:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
show_config() {
|
||||||
|
# do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_config() {
|
||||||
|
# do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
show) show_config;;
|
||||||
|
apply) apply_config;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
#### The "show" part
|
||||||
|
|
||||||
|
The show part is when the user ask to see the current state of the
|
||||||
|
configuration panel (like opening to configuration panel page on the admin
|
||||||
|
interface). The role of the scripts/config script here is to gather all the
|
||||||
|
relevant information, by for example parsing a configuration file or querying a
|
||||||
|
database, and communicate it to YunoHost. To do so, you need to use the helper
|
||||||
|
`ynh_return` like so:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ynh_return "YNH_CONFIG_SOME_VARIABLE_NAME=some_value"
|
||||||
|
```
|
||||||
|
|
||||||
|
For example, for this config_panel:
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[main]
|
||||||
|
name = "Leed configuration"
|
||||||
|
|
||||||
|
[main.is_public]
|
||||||
|
name = "Public access"
|
||||||
|
|
||||||
|
# those arguments are in yunohost argument format
|
||||||
|
[main.is_public.is_public]
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
You would do:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ynh_return "YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC=1"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you don't provide any value for a configuration **the default value will be used**.
|
||||||
|
|
||||||
|
Expanding our previous example you would have this scripts/config script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
show_config() {
|
||||||
|
ynh_return "YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC=1"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_config() {
|
||||||
|
# do stuff
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
show) show_config;;
|
||||||
|
apply) apply_config;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
#### The "apply" part
|
||||||
|
|
||||||
|
The "apply" part is called when the user click on "submit" on the configuration
|
||||||
|
page on the admin interface. This part is simpler to write:
|
||||||
|
|
||||||
|
- the scripts/config will be called with "apply"
|
||||||
|
- all the value in the config panel (modified or not) are available as global
|
||||||
|
variable in the script following the format `YNH_{section_id}_{sub_section_id}_{option_id}`
|
||||||
|
(exactly the same than for show)
|
||||||
|
- the script is responsible for doing whatever it wants with those information
|
||||||
|
- once the script as succeeded, the admin interface display the config panel
|
||||||
|
again so the script is called again in "show" mode
|
||||||
|
|
||||||
|
Expanding the previous script that could look like that:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
show_config() {
|
||||||
|
ynh_return "YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC=1"
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_config() {
|
||||||
|
value=$YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC
|
||||||
|
# do some stuff with value
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
show) show_config;;
|
||||||
|
apply) apply_config;;
|
||||||
|
esac
|
||||||
|
```
|
||||||
|
|
||||||
|
Or if you want a full useless simple script that store the value in a file,
|
||||||
|
this can looks like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dummy_config_file="dummy_config_file.ini"
|
||||||
|
|
||||||
|
show_config() {
|
||||||
|
if [ -e $dummy_config_file ]
|
||||||
|
then
|
||||||
|
ynh_return "YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC=$(cat $dummy_config_file)"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# the default value will be used
|
||||||
|
}
|
||||||
|
|
||||||
|
apply_config() {
|
||||||
|
echo $YNH_CONFIG_MAIN_IS_PUBLIC_IS_PUBLIC > $dummy_config_file
|
||||||
|
}
|
||||||
|
|
||||||
|
case $1 in
|
||||||
|
show) show_config;;
|
||||||
|
apply) apply_config;;
|
||||||
|
esac
|
||||||
|
```
|
Loading…
Reference in a new issue