mirror of
https://github.com/YunoHost/doc.git
synced 2024-09-03 20:06:26 +02:00
configpanel: misc typo, wording, examples improvements
This commit is contained in:
parent
ecbda6efba
commit
c6bdbcefee
1 changed files with 143 additions and 119 deletions
|
@ -1,5 +1,5 @@
|
||||||
---
|
---
|
||||||
title: Config panels
|
title: Configuration panel for apps
|
||||||
template: docs
|
template: docs
|
||||||
taxonomy:
|
taxonomy:
|
||||||
category: docs
|
category: docs
|
||||||
|
@ -7,28 +7,27 @@ routes:
|
||||||
default: '/packaging_config_panels'
|
default: '/packaging_config_panels'
|
||||||
---
|
---
|
||||||
|
|
||||||
# Configuration panel for apps
|
Configuration panels allow to let admins manage parameters or runs actions for which the upstream's app doesn't provide any appropriate UI itself. It's a good way to reduce manual change on config files and avoid conflicts on it.
|
||||||
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.).
|
Those panels can also be used to quickly create interfaces that extend the 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.
|
! Please: Keep in mind the YunoHost spirit, and try to build your panels in such a way as to expose only really useful, "high-level" parameters, and if there are many of them, to relegate those corresponding to rarer use cases to "Advanced" sub-sections. Keep it simple, focus on common needs, don't expect the admins to have 3 PhDs in computer science.
|
||||||
|
|
||||||
## How does `config_panel.toml` work
|
## `config_panel.toml`'s principle and general format
|
||||||
|
|
||||||
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.
|
To create configuration panels for apps, you should at least create a `config_panel.toml` at the root of the package. For more complex cases, this TOML file can be paired with a `config` script inside the scripts directory of your package, which will handle specific controller logic.
|
||||||
|
|
||||||
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.
|
The `config_panel.toml` describes one or several panels, containing sections, each containing questions generally binded to a params in the app's actual configuration files.
|
||||||
|
|
||||||
We supposed we have an upstream app with this simple config.yml file:
|
Let's imagine that the upstream app is configured using this simple `config.yml` file stored in the app's install directory (typically `/var/www/$app/config.yml`):
|
||||||
```yaml
|
```yaml
|
||||||
title: 'My dummy apps'
|
title: 'My dummy app'
|
||||||
theme: 'white'
|
theme: 'white'
|
||||||
max_rate: 10
|
max_rate: 10
|
||||||
max_age: 365
|
max_age: 365
|
||||||
```
|
```
|
||||||
|
|
||||||
We could for example create a simple configuration panel for it like this one, by following the syntax `\[PANEL.SECTION.QUESTION\]`:
|
We could for example create a simple configuration panel for it like this one, by following the syntax `[PANEL.SECTION.QUESTION]`:
|
||||||
```toml
|
```toml
|
||||||
version = "1.0"
|
version = "1.0"
|
||||||
[main]
|
[main]
|
||||||
|
@ -60,72 +59,92 @@ 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.
|
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
|
### 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
|
For performance reasons, questions short keys have to be unique in all the `config_panel.toml` file, not just inside its panel or its section. Hence it's not possible to have:
|
||||||
```toml
|
```toml
|
||||||
[manual.vpn.server_ip]
|
[manual.vpn.server_ip]
|
||||||
[advanced.dns.server_ip]
|
[advanced.dns.server_ip]
|
||||||
```
|
```
|
||||||
Indeed the real variable name is server_ip and here you have a conflict.
|
In which two questions have "real variable name" `is server_ip` and therefore conflict with each other.
|
||||||
|
|
||||||
|
### Supported questions types and properties
|
||||||
|
|
||||||
## Panels, sections and questions properties
|
|
||||||
See [the full list of questions types and properties](/dev/forms)
|
See [the full list of questions types and properties](/dev/forms)
|
||||||
|
|
||||||
|
|
||||||
## Read and write values
|
### Reading and writing 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.
|
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
|
### `bind` property
|
||||||
|
|
||||||
The `bind` property allows to define where read and write the value bind to the question.
|
The `bind` property allows to define where read and write the value bind to the question.
|
||||||
|
|
||||||
#### Default behaviour
|
#### 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.
|
If you did not define a specific getter/setter (see below), and no `bind` argument was defined, YunoHost will read/write the value from/to the app's `/etc/yunohost/$app/settings.yml` file.
|
||||||
|
|
||||||
#### Read / write into a var of a configuration file
|
#### Read / write into a var of an actual 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:
|
If you want to read/write the value from/to the app's actual configural file (be it `.env`-like, JSON, YAML, INI, PHP, `.py`, ...):
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
|
[main.main.theme]
|
||||||
|
# (other properties ommited)
|
||||||
bind = ":__INSTALL_DIR__/config.yml"
|
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:
|
In which case, YunoHost will look for something like a key/value, with the key being `theme`.
|
||||||
|
|
||||||
|
If the question id in the config panel (here, `theme`) differs from the key in the actual conf file (let's say it's not `theme` but `css_theme`), then you can write:
|
||||||
```toml
|
```toml
|
||||||
bind = "email:__FINALPATH__/config.yml"
|
[main.main.theme]
|
||||||
|
# (other properties ommited)
|
||||||
|
bind = "css_theme:__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.
|
!!!! Note: This mechanism is quasi language agnostic and will use regexes to find something that looks like a key=value or common variants. However, it does assume that the key and value are stored on the same line. It doesn't support multiline text or file in a variable with this method. If you need to save multiline content in a configuration variable, you should create a custom getter/setter (see below).
|
||||||
|
|
||||||
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:
|
Nested syntax is also supported, which may be useful for example to remove ambiguities about stuff looking like:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"foo": {
|
||||||
|
"max": 123
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
"max": 456
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
which we can `bind` to using:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
bind = "importExportRateLimiting>max:__INSTALL_DIR__/conf.json"
|
bind = "foo>max:__INSTALL_DIR__/conf.json"
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Read / write an entire file
|
#### 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.
|
Useful when using a question `file` or `text` for which you want to save the raw content directly as a file on the system.
|
||||||
```toml
|
```toml
|
||||||
|
[main.main.logo]
|
||||||
|
# (other properties ommited)
|
||||||
bind = "__INSTALL_DIR__/img/logo.png"
|
bind = "__INSTALL_DIR__/img/logo.png"
|
||||||
```
|
```
|
||||||
|
|
||||||
### Specific getter / setter
|
### Custom getter / setter
|
||||||
|
|
||||||
Sometimes the `bind` mechanism is not enough:
|
Sometimes the `bind` mechanism is not enough:
|
||||||
* the config file format is not supported (e.g. xml, csv)
|
* 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 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 written but not read (e.g. password)
|
||||||
* the data should be read but not writen (e.g. status information)
|
* the data should be read but not written (e.g. fetching status information)
|
||||||
* we want to change other things than the value (e.g. the choices list of a select)
|
* 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
|
* the question answer contains several values to dispatch in several places
|
||||||
* and so on
|
* and so on
|
||||||
|
|
||||||
For all of those use cases, there are the specific getter or setter mechanism for a question !
|
You can create specific getter/setters functions inside the `scripts/config` of your app to customize how the information is read/written.
|
||||||
|
|
||||||
To create specific getter / setter, you first need to create a `config` script inside the `scripts` directory
|
|
||||||
|
|
||||||
scripts/config
|
|
||||||
```bash
|
```bash
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
source /usr/share/yunohost/helpers
|
source /usr/share/yunohost/helpers
|
||||||
|
@ -140,52 +159,65 @@ ynh_app_config_run $1
|
||||||
|
|
||||||
#### Getter
|
#### Getter
|
||||||
|
|
||||||
A getter is a bash function called `getter_QUESTION_SHORT_KEY()` which returns data through stdout.
|
A question's getter is the function used to read the current value/state. Custom getters are defined using bash functions called `getter__QUESTION_SHORT_KEY()` which returns data through stdout.
|
||||||
|
|
||||||
Returns could have 2 formats:
|
Stdout can generated using one of those formats:
|
||||||
* a raw format, in this case the return is binded directly to the value of the question
|
1) either a raw format, in which 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.)
|
2) or a yaml format, in this case you dynamically provide properties for your question (for example the `style` of an `alert`, the list of available `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"]
|
[details summary="<i>Basic example with raw stdout: get the timezone on the system</i>" class="helper-card-subtitle text-muted"]
|
||||||
scripts/config
|
|
||||||
```bash
|
`config_panel.toml`
|
||||||
get__login_user() {
|
|
||||||
if [ -s /etc/openvpn/keys/credentials ]
|
```toml
|
||||||
then
|
[main.main.timezone]
|
||||||
echo "$(sed -n 1p /etc/openvpn/keys/credentials)"
|
ask = "Timezone"
|
||||||
else
|
type = "string"
|
||||||
echo ""
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
config_panel.toml
|
`scripts/config`
|
||||||
```toml
|
|
||||||
[main.auth.login_user]
|
```bash
|
||||||
ask = "Username"
|
get__timezone() {
|
||||||
type = "string"
|
echo "$(cat /etc/timezone)"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
[/details]
|
[/details]
|
||||||
|
|
||||||
[details summary="<i>Advanced example 1 : Display a list of available plugins</i>" class="helper-card-subtitle text-muted"]
|
[details summary="<i>Basic example with yaml-formated stdout : Display a list of available plugins</i>" class="helper-card-subtitle text-muted"]
|
||||||
scripts/config
|
|
||||||
```bash
|
|
||||||
get__plugins() {
|
|
||||||
echo "choices: [$(ls $install_dir/plugins/ | tr '\n' ',')]"
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
config_panel.toml
|
`config_panel.toml`
|
||||||
```toml
|
```toml
|
||||||
[main.plugins.plugins]
|
[main.plugins.plugins]
|
||||||
ask = "Plugin to activate"
|
ask = "Plugin to activate"
|
||||||
type = "tags"
|
type = "tags"
|
||||||
choices = []
|
choices = []
|
||||||
```
|
```
|
||||||
|
|
||||||
|
`scripts/config`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
get__plugins() {
|
||||||
|
echo "choices: [$(ls $install_dir/plugins/ | tr '\n' ',')]"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
[/details]
|
[/details]
|
||||||
|
|
||||||
[details summary="<i>Example 2 : Display the status of a VPN</i>" class="helper-card-subtitle text-muted"]
|
[details summary="<i>Advanced example with yaml-formated stdout : Display the status of a VPN</i>" class="helper-card-subtitle text-muted"]
|
||||||
scripts/config
|
|
||||||
|
`config_panel.toml`
|
||||||
|
|
||||||
|
```toml
|
||||||
|
[main.cube.status]
|
||||||
|
ask = "Custom getter alert"
|
||||||
|
type = "alert"
|
||||||
|
style = "info"
|
||||||
|
bind = "null" # no behaviour on
|
||||||
|
```
|
||||||
|
|
||||||
|
`scripts/config`
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
get__status() {
|
get__status() {
|
||||||
if [ -f "/sys/class/net/tun0/operstate" ] && [ "$(cat /sys/class/net/tun0/operstate)" == "up" ]
|
if [ -f "/sys/class/net/tun0/operstate" ] && [ "$(cat /sys/class/net/tun0/operstate)" == "up" ]
|
||||||
|
@ -204,44 +236,36 @@ EOF
|
||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
config_panel.toml
|
|
||||||
```toml
|
|
||||||
[main.cube.status]
|
|
||||||
ask = "Custom getter alert"
|
|
||||||
type = "alert"
|
|
||||||
style = "info"
|
|
||||||
bind = "null" # no behaviour on
|
|
||||||
```
|
|
||||||
[/details]
|
[/details]
|
||||||
|
|
||||||
#### Setter
|
#### 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.
|
A question's setter is the function used to set new value/state. Custom setters are defined using bash functions called `setter__QUESTION_SHORT_KEY()`. In the context of the setter function, variables named with the various quetion's short keys are avaible ... for example the user-specified date for question `[main.main.theme]` is available as `$theme`.
|
||||||
|
|
||||||
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.
|
When doing non-trivial operations to set a value, you may want to use `ynh_print_info` to inform the admin about what's going on.
|
||||||
|
|
||||||
[details summary="<i>Basic example : Set the login into the first line of a file </i>" class="helper-card-subtitle text-muted"]
|
[details summary="<i>Basic example : Set the system timezone</i>" class="helper-card-subtitle text-muted"]
|
||||||
scripts/config
|
|
||||||
```bash
|
`config_panel.toml`
|
||||||
set__login_user() {
|
|
||||||
if [ -z "${login_user}" ]
|
```toml
|
||||||
then
|
[main.main.timezone]
|
||||||
echo "${login_user}" > /etc/openvpn/keys/credentials
|
ask = "Timezone"
|
||||||
ynh_print_info "The user login has been registered in /etc/openvpn/keys/credentials"
|
type = "string"
|
||||||
fi
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
config_panel.toml
|
`scripts/config`
|
||||||
```toml
|
|
||||||
[main.auth.login_user]
|
```bash
|
||||||
ask = "Username"
|
set__timezone() {
|
||||||
type = "string"
|
echo "$timezone" > /etc/timezone
|
||||||
|
ynh_print_info "The timezone has been changed to $timezone"
|
||||||
|
}
|
||||||
```
|
```
|
||||||
[/details]
|
[/details]
|
||||||
|
|
||||||
## Validation
|
## Validation
|
||||||
|
|
||||||
You will often need to validate data answered by the user before to save it somewhere.
|
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
|
Validation can be made with regex through `pattern` argument
|
||||||
|
@ -252,9 +276,9 @@ Validation can be made with regex through `pattern` argument
|
||||||
|
|
||||||
You can also restrict several types with a choices list.
|
You can also restrict several types with a choices list.
|
||||||
```toml
|
```toml
|
||||||
choices.option1 = "Plop1"
|
choices.foo = "Foo (some explanation)"
|
||||||
choices.option2 = "Plop2"
|
choices.bar = "Bar (moar explanation)"
|
||||||
choices.option3 = "Plop3"
|
choices.loremipsum = "Lorem Ipsum Dolor Sit Amet"
|
||||||
```
|
```
|
||||||
|
|
||||||
Some other type specific argument exist like
|
Some other type specific argument exist like
|
||||||
|
@ -267,7 +291,7 @@ Some other type specific argument exist like
|
||||||
Finally, if you need specific or multi variable validation, you can use custom validators function:
|
Finally, if you need specific or multi variable validation, you can use custom validators function:
|
||||||
```bash
|
```bash
|
||||||
validate__login_user() {
|
validate__login_user() {
|
||||||
if [[ "${#login_user}" -lt 4 ]]; then echo 'Too short user login'; fi
|
if [[ "${#login_user}" -lt 4 ]]; then echo 'User login is too short, should be at least 4 chars'; fi
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -275,13 +299,13 @@ validate__login_user() {
|
||||||
|
|
||||||
### Restart a service at the end
|
### Restart a service at the end
|
||||||
|
|
||||||
You can use the services key to specify which service need to be reloaded or restarted
|
You can use the services key to specify which service need to be reloaded or restarted.
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
services = [ 'nginx', '__APP__' ]
|
services = [ 'nginx', '__APP__' ]
|
||||||
```
|
```
|
||||||
|
|
||||||
This argument could be on panel, section, or question.
|
This argument can be set on a single question, to a section, or to an entire panel.
|
||||||
|
|
||||||
### Overwrite config panel mechanism
|
### Overwrite config panel mechanism
|
||||||
|
|
||||||
|
@ -304,10 +328,10 @@ ynh_app_config_apply() {
|
||||||
```
|
```
|
||||||
|
|
||||||
List of main configuration helpers
|
List of main configuration helpers
|
||||||
* ynh_app_config_get
|
* `ynh_app_config_get`
|
||||||
* ynh_app_config_show
|
* `ynh_app_config_show`
|
||||||
* ynh_app_config_validate
|
* `ynh_app_config_validate`
|
||||||
* ynh_app_config_apply
|
* `ynh_app_config_apply`
|
||||||
* ynh_app_config_run
|
* `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)
|
More info on this can be found by reading [vpnclient_ynh config script](https://github.com/YunoHost-Apps/vpnclient_ynh/blob/master/scripts/config)
|
||||||
|
|
Loading…
Add table
Reference in a new issue