mirror of
https://github.com/YunoHost/doc.git
synced 2024-09-03 20:06:26 +02:00
[enh] Add config panel docs
This commit is contained in:
parent
f44109e3bb
commit
07c602e9d0
2 changed files with 431 additions and 1 deletions
|
@ -7,4 +7,295 @@ routes:
|
||||||
default: '/packaging_config_panels'
|
default: '/packaging_config_panels'
|
||||||
---
|
---
|
||||||
|
|
||||||
TODO / FIXME ...
|
# Configuration panel for apps
|
||||||
|
Configuration panels for apps allows to let instances adminitrators manage some parameters or runs some actions for which the upstream doesn't provide any configuration panels itself. It's a good way to reduce manual change on config files and avoid conflicts on it.
|
||||||
|
|
||||||
|
Those panels could aslo be used as interface generator to extend quickly capabilities of YunoHost (e.g. VPN Client, Hotspost, Borg, etc.).
|
||||||
|
|
||||||
|
! Please: Keep in mind the YunoHost spirit, and try to build your panels in such a way as to expose only really useful parameters, and if there are many of them, to relegate those corresponding to rarer use cases to "Advanced" sub-sections.
|
||||||
|
|
||||||
|
## How does config_panel.toml work
|
||||||
|
|
||||||
|
Basically, configuration panels for apps uses at least a `config_panel.toml` at the root of your package. For advanced usecases, this TOML file could also be paired with a `config` script inside the scripts directory of your package.
|
||||||
|
|
||||||
|
The `config_panel.toml` file describes one or several panels, containing some sections, containing some questions generally binded to a params in a configuration file.
|
||||||
|
|
||||||
|
We supposed we have an upstream app with this simple config.yml file:
|
||||||
|
```
|
||||||
|
title: 'My dummy apps'
|
||||||
|
theme: 'white'
|
||||||
|
max_rate: 10
|
||||||
|
max_age: 365
|
||||||
|
```
|
||||||
|
|
||||||
|
We could for example create a simple configuration panel for it like this one, by following the syntax `\[PANEL.SECTION.QUESTION\]`:
|
||||||
|
```
|
||||||
|
version = "1.0"
|
||||||
|
[main]
|
||||||
|
|
||||||
|
[main.main]
|
||||||
|
[main.main.title]
|
||||||
|
ask.en = "Title"
|
||||||
|
type = "string"
|
||||||
|
bind = ":__INSTALL_DIR__/config.yml"
|
||||||
|
|
||||||
|
[main.main.theme]
|
||||||
|
ask.en = "Theme"
|
||||||
|
type = "select"
|
||||||
|
choices = ["white", "dark"]
|
||||||
|
bind = ":__INSTALL_DIR__/config.yml"
|
||||||
|
|
||||||
|
[main.limits]
|
||||||
|
[main.limits.max_rate]
|
||||||
|
ask.en = "Maximum display rate"
|
||||||
|
type = "number"
|
||||||
|
bind = ":__INSTALL_DIR__/config.yml"
|
||||||
|
|
||||||
|
[main.limits.max_age]
|
||||||
|
ask.en = "Duration of a dummy"
|
||||||
|
type = "number"
|
||||||
|
bind = ":__INSTALL_DIR__/config.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
Here we have created one `main` panel, containing the `main` and `limits` sections, containing questions according to params name of our `config.yml` file. Thanks to the `bind` properties, all those questions are bind to their values in the `config.yml` file.
|
||||||
|
|
||||||
|
### Questions short keys have to be unique
|
||||||
|
For performance reasons, questions short keys should be unique in all the `config_panel.toml` file, not just inside its panel or its section.
|
||||||
|
|
||||||
|
So you can't have
|
||||||
|
```
|
||||||
|
[manual.vpn.server_ip]
|
||||||
|
[advanced.dns.server_ip]
|
||||||
|
```
|
||||||
|
Indeed the real variable name is server_ip and here you have a conflict.
|
||||||
|
|
||||||
|
## Panels, sections and questions properties
|
||||||
|
See [the full list of questions types and properties](/dev/forms)
|
||||||
|
|
||||||
|
|
||||||
|
## Read and write values
|
||||||
|
You can read and write values with 2 mechanisms: the `bind` property in the `config_panel.toml` and for complex use cases the getter/setter in a `config` script.
|
||||||
|
|
||||||
|
### `bind` property
|
||||||
|
The `bind` property allows to define where read and write the value bind to the question.
|
||||||
|
|
||||||
|
#### Default behaviour
|
||||||
|
|
||||||
|
If you have not defined a specific getter/setter (see bellow), and without `bind` argument it will read and save the value in app settings yaml file.
|
||||||
|
|
||||||
|
#### Read / write into a var of a configuration file
|
||||||
|
|
||||||
|
If you want to read and save the value into a variable (called like the option name) of a file (json, yaml, ini, php, py ...) you can do:
|
||||||
|
|
||||||
|
```
|
||||||
|
bind = ":__INSTALL_DIR__/config.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to read and save the value into an other variable than the `config_panel.toml` question short key (email in the example) of a file (json, yaml, ini, php, py ...) you can do:
|
||||||
|
```
|
||||||
|
bind = "email:__FINALPATH__/config.yml"
|
||||||
|
```
|
||||||
|
|
||||||
|
!!!! Note: This mechanism is quasi language agnostic, however it's monoline: you can't save multiline text or file in a variable with this method. If you need to save multiline content in a configuration variable, you should do it via a specific getter/setter.
|
||||||
|
|
||||||
|
Sometimes, you want to read and save a value in a variable name that appears several time in the configuration file (for example variables called `max`). The `bind` property allows you to change the value on the variable following a regex in a the file:
|
||||||
|
|
||||||
|
```
|
||||||
|
bind = "importExportRateLimiting>max:__INSTALL_DIR__/conf.json"
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Read / write an entire file
|
||||||
|
|
||||||
|
If you have a question of type file or text you could want to save the content into a specific path on the system.
|
||||||
|
```
|
||||||
|
bind = "__INSTALL_DIR__/img/logo.png"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Specific getter / setter
|
||||||
|
Sometimes the `bind` mechanism is not enough:
|
||||||
|
* the config file format is not supported (e.g. xml, csv)
|
||||||
|
* the data is not contained in a config file (e.g. database, directory, web resources...)
|
||||||
|
* the data should be writen but not read (e.g. password)
|
||||||
|
* the data should be read but not writen (e.g. status information)
|
||||||
|
* we want to change other things than the value (e.g. the choices list of a select)
|
||||||
|
* the question answer contains several values to dispatch in several places
|
||||||
|
* and so on
|
||||||
|
|
||||||
|
For all of those use cases, there are the specific getter or setter mechanism for a question !
|
||||||
|
|
||||||
|
To create specific getter / setter, you first need to create a `config` script inside the `scripts` directory
|
||||||
|
|
||||||
|
#### Getter
|
||||||
|
|
||||||
|
A getter is a bash function called `getter_QUESTION_SHORT_KEY()` which returns data through stdout.
|
||||||
|
|
||||||
|
Returns could have 2 formats:
|
||||||
|
* a raw format, in this case the return is binded directly to the value of the question
|
||||||
|
* a yaml format, in this case you can rewrite several properties of your question (like the `style` of an `alert`, the list of `choices` of a `select`, etc.)
|
||||||
|
|
||||||
|
[details summary="<i>Basic example : Get the login inside the first line of a file </i>" class="helper-card-subtitle text-muted"]
|
||||||
|
scripts/config
|
||||||
|
```
|
||||||
|
get__login_user() {
|
||||||
|
if [ -s /etc/openvpn/keys/credentials ]
|
||||||
|
then
|
||||||
|
echo "$(sed -n 1p /etc/openvpn/keys/credentials)"
|
||||||
|
else
|
||||||
|
echo ""
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
config_panel.toml
|
||||||
|
```
|
||||||
|
[main.auth.login_user]
|
||||||
|
ask = "Username"
|
||||||
|
type = "string"
|
||||||
|
```
|
||||||
|
[/details]
|
||||||
|
|
||||||
|
[details summary="<i>Advanced example 1 : Display a list of available plugins</i>" class="helper-card-subtitle text-muted"]
|
||||||
|
scripts/config
|
||||||
|
```
|
||||||
|
get__plugins() {
|
||||||
|
echo "choices: [$(ls $install_dir/plugins/ | tr '\n' ',')]"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
config_panel.toml
|
||||||
|
```
|
||||||
|
[main.plugins.plugins]
|
||||||
|
ask = "Plugin to activate"
|
||||||
|
type = "tags"
|
||||||
|
choices = []
|
||||||
|
```
|
||||||
|
[/details]
|
||||||
|
|
||||||
|
[details summary="<i>Example 2 : Display the status of a VPN</i>" class="helper-card-subtitle text-muted"]
|
||||||
|
scripts/config
|
||||||
|
```
|
||||||
|
get__status() {
|
||||||
|
if [ -f "/sys/class/net/tun0/operstate" ] && [ "$(cat /sys/class/net/tun0/operstate)" == "up" ]
|
||||||
|
then
|
||||||
|
cat << EOF
|
||||||
|
style: success
|
||||||
|
ask:
|
||||||
|
en: Your VPN is running :)
|
||||||
|
EOF
|
||||||
|
else
|
||||||
|
cat << EOF
|
||||||
|
style: danger
|
||||||
|
ask:
|
||||||
|
en: Your VPN is down
|
||||||
|
EOF
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
config_panel.toml
|
||||||
|
```
|
||||||
|
[main.cube.status]
|
||||||
|
ask = "Custom getter alert"
|
||||||
|
type = "alert"
|
||||||
|
style = "info"
|
||||||
|
bind = "null" # no behaviour on
|
||||||
|
```
|
||||||
|
[/details]
|
||||||
|
|
||||||
|
#### Setter
|
||||||
|
|
||||||
|
A setter is a bash function called `setter_QUESTION()`. This function could access new values defined by the users by using bash variable with the same name as the short key of a question.
|
||||||
|
|
||||||
|
You probably should use `ynh_print_info` in order to display info for user about change that has been made to help them to understand a bit what's going.
|
||||||
|
|
||||||
|
[details summary="<i>Basic example : Set the login into the first line of a file </i>" class="helper-card-subtitle text-muted"]
|
||||||
|
scripts/config
|
||||||
|
```
|
||||||
|
set__login_user() {
|
||||||
|
if [ -z "${login_user}" ]
|
||||||
|
then
|
||||||
|
echo "${login_user}" > /etc/openvpn/keys/credentials
|
||||||
|
ynh_print_info "The user login has been registered in /etc/openvpn/keys/credentials"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
config_panel.toml
|
||||||
|
```
|
||||||
|
[main.auth.login_user]
|
||||||
|
ask = "Username"
|
||||||
|
type = "string"
|
||||||
|
```
|
||||||
|
[/details]
|
||||||
|
|
||||||
|
## Validation
|
||||||
|
You will often need to validate data answered by the user before to save it somewhere.
|
||||||
|
|
||||||
|
Validation can be made with regex through `pattern` argument
|
||||||
|
```
|
||||||
|
pattern.regexp = '^.+@.+$'
|
||||||
|
pattern.error = 'An email is required for this field'
|
||||||
|
```
|
||||||
|
|
||||||
|
You can also restrict several types with a choices list.
|
||||||
|
```
|
||||||
|
choices.option1 = "Plop1"
|
||||||
|
choices.option2 = "Plop2"
|
||||||
|
choices.option3 = "Plop3"
|
||||||
|
```
|
||||||
|
|
||||||
|
Some other type specific argument exist like
|
||||||
|
| type | validation arguments |
|
||||||
|
| ----- | --------------------------- |
|
||||||
|
| `number`, `range` | `min`, `max`, `step` |
|
||||||
|
| `file` | `accept` |
|
||||||
|
| `tags` | `limit` |
|
||||||
|
| `boolean` | `yes` `no` |
|
||||||
|
|
||||||
|
Finally, if you need specific or multi variable validation, you can use custom validators function:
|
||||||
|
```
|
||||||
|
validate__login_user() {
|
||||||
|
if [[ "${#login_user}" -lt 4 ]]; then echo 'Too short user login'; fi
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Other actions than read, validate and save
|
||||||
|
|
||||||
|
### Restart a service at the end
|
||||||
|
|
||||||
|
You can use the services key to specify which service need to be reloaded or restarted
|
||||||
|
|
||||||
|
```
|
||||||
|
services = [ 'nginx', '__APP__' ]
|
||||||
|
```
|
||||||
|
|
||||||
|
This argument could be on panel, section, or question.
|
||||||
|
|
||||||
|
### Overwrite config panel mechanism
|
||||||
|
|
||||||
|
All main configuration helpers are overwritable, example:
|
||||||
|
|
||||||
|
```
|
||||||
|
ynh_app_config_apply() {
|
||||||
|
|
||||||
|
# Stop vpn client
|
||||||
|
touch /tmp/.ynh-vpnclient-stopped
|
||||||
|
systemctl stop ynh-vpnclient
|
||||||
|
|
||||||
|
_ynh_app_config_apply
|
||||||
|
|
||||||
|
# Start vpn client
|
||||||
|
systemctl start ynh-vpnclient
|
||||||
|
rm -f /tmp/.ynh-vpnclient-stopped
|
||||||
|
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
List of main configuration helpers
|
||||||
|
* ynh_app_config_get
|
||||||
|
* ynh_app_config_show
|
||||||
|
* ynh_app_config_validate
|
||||||
|
* ynh_app_config_apply
|
||||||
|
* ynh_app_config_run
|
||||||
|
|
||||||
|
More info on this could be found by reading [vpnclient_ynh config script](https://github.com/YunoHost-Apps/vpnclient_ynh/blob/master/scripts/config)
|
||||||
|
|
139
pages/06.contribute/15.dev/03.forms/forms.md
Normal file
139
pages/06.contribute/15.dev/03.forms/forms.md
Normal file
|
@ -0,0 +1,139 @@
|
||||||
|
---
|
||||||
|
title: Forms
|
||||||
|
template: docs
|
||||||
|
taxonomy:
|
||||||
|
category: docs
|
||||||
|
routes:
|
||||||
|
default: '/dev/forms'
|
||||||
|
---
|
||||||
|
|
||||||
|
# Forms
|
||||||
|
|
||||||
|
YunoHost uses a lot of forms. You can found here information on supported types question and properties.
|
||||||
|
|
||||||
|
## Questions
|
||||||
|
!!! Questions are called `Options` in the code.
|
||||||
|
|
||||||
|
### Generic properties
|
||||||
|
|
||||||
|
| Property | Scope | Description | Example |
|
||||||
|
|----------|--------------|-------------|---------|
|
||||||
|
| `type` | Everywhere | Specify the type of the question (see bellow for the list) | |
|
||||||
|
| `ask` | Everywhere | The title of the question | `ask.en = "Cats or dogs ?"` |
|
||||||
|
| `help` | Everywhere | An help message | `help.en = "Think carefully!"` |
|
||||||
|
| `optional`| Everywhere | Set true if the question is not mandatory | `optional = true` |
|
||||||
|
| `readonly`| Everywhere | Avoid user to be able to change the value | `readonly = true` |
|
||||||
|
| `example` | Everywhere | Give an example to help to understand the format of the answer||
|
||||||
|
| `pattern.regexp` | Everywhere | Regex to validate the new value||
|
||||||
|
| `pattern.error` | Everywhere | Error to display if the pattern doesn't match ||
|
||||||
|
| `redact` | Everywhere | Avoid a confidential value to be logged | `redact = true` |
|
||||||
|
| `default` | Install | A default value for the question | |
|
||||||
|
| `visible` | ConfigPanel | A simple js expression based on other short keys questions to hide or display dynamically the question| `visible = "login && ! private_key"` |
|
||||||
|
| `bind` | AppConfigPanel | See [App configuration panel doc](/packaging_config_panels) |
|
||||||
|
|
||||||
|
* `help`, `optional`, `readonly` and `visible` are also available on panels and sections entities.
|
||||||
|
* Long help messages could not to be correctly displayed for user using yunohost CLI
|
||||||
|
* For the moment `default` properties are not supported in app config panel and you have to initialize the value by yourself in config file or settings.
|
||||||
|
|
||||||
|
|
||||||
|
### `display_text` (readonly)
|
||||||
|
Display a simple text.
|
||||||
|
|
||||||
|
### `markdown` (readonly)
|
||||||
|
Display a markdown (if you don't use markdown features, prefer display_text)
|
||||||
|
|
||||||
|
### `alert` (readonly)
|
||||||
|
Display an alert box with different style.
|
||||||
|
|
||||||
|
| Property | Description | Default |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `style` | Style of the alert box (success, info, warning, danger) | info |
|
||||||
|
|
||||||
|
### `button`
|
||||||
|
Display a button with different style (useful for custom actions).
|
||||||
|
|
||||||
|
| Property | Description | Default |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `style` | Style of the alert box (success, info, warning, danger) | success|
|
||||||
|
| `enabled` | Enable or disable the button | True |
|
||||||
|
|
||||||
|
### `string`
|
||||||
|
Input text monoline.
|
||||||
|
|
||||||
|
### `text`
|
||||||
|
Input text multilines
|
||||||
|
|
||||||
|
| Property | Description | Default |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `redact` | Style of the alert box (success, info, warning, danger) | success|
|
||||||
|
|
||||||
|
### `password`
|
||||||
|
Password input. `{}` chars are forbidden and value is not added to logs.
|
||||||
|
|
||||||
|
### `color`
|
||||||
|
Hexadecimal color starting with # with a color picker.
|
||||||
|
|
||||||
|
### `number`
|
||||||
|
An integer.
|
||||||
|
|
||||||
|
| Property | Description | Example |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `min` | Minimal value | |
|
||||||
|
| `max` | Maximum value | |
|
||||||
|
| `step` | Steps between each next possible value | |
|
||||||
|
|
||||||
|
### `range`
|
||||||
|
| Property | Description | Example |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `min` | Minimal value | |
|
||||||
|
| `max` | Maximum value | |
|
||||||
|
| `step` | Steps between each next possible value | |
|
||||||
|
|
||||||
|
### `boolean`
|
||||||
|
| Property | Description | Example |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `yes` | | |
|
||||||
|
| `no` | | |
|
||||||
|
|
||||||
|
### `date`
|
||||||
|
A date picker with date in the format YYYY-MM-DD
|
||||||
|
|
||||||
|
### `time`
|
||||||
|
A time picker
|
||||||
|
|
||||||
|
### `email`
|
||||||
|
An email input
|
||||||
|
|
||||||
|
### `path`
|
||||||
|
### `url`
|
||||||
|
By default it ask for a web URL but you can change the `pattern` if you want to.
|
||||||
|
|
||||||
|
### `file`
|
||||||
|
File question
|
||||||
|
| Property | Description | Example |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `accept` | Same format than HTML file input | |
|
||||||
|
|
||||||
|
! This file type is not made for big files transfer, it's just for small logo, or config files.
|
||||||
|
|
||||||
|
### `select`
|
||||||
|
| Property | Description | Example |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `choices` | list or dictionary of choices | |
|
||||||
|
|
||||||
|
### `tags`
|
||||||
|
| Property | Description | Example |
|
||||||
|
|----------|--------------|---------|
|
||||||
|
| `choices` | List or dictionary of choices | |
|
||||||
|
|
||||||
|
### `domain`
|
||||||
|
List all added domains
|
||||||
|
|
||||||
|
### `app`
|
||||||
|
List all installed apps
|
||||||
|
|
||||||
|
### `user`
|
||||||
|
List all users
|
||||||
|
|
||||||
|
### `group`
|
||||||
|
List all groups
|
Loading…
Add table
Reference in a new issue