mirror of
https://github.com/YunoHost/yunohost.git
synced 2024-09-03 20:06:10 +02:00
doc:config: add ljf's advanced config panel doc
This commit is contained in:
parent
d676348d35
commit
ee72d2f463
4 changed files with 329 additions and 160 deletions
|
@ -82,3 +82,78 @@ for c in OptionClasses:
|
|||
print("")
|
||||
print(doc)
|
||||
print("")
|
||||
|
||||
|
||||
print(
|
||||
"""
|
||||
## Full example
|
||||
|
||||
We supposed we have an upstream app with this simple config.yml file:
|
||||
```yaml
|
||||
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\]`:
|
||||
```toml
|
||||
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.
|
||||
|
||||
## Overwrite config panel mechanism
|
||||
|
||||
All main configuration helpers are overwritable, example:
|
||||
|
||||
```bash
|
||||
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)
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -132,83 +132,60 @@ print(
|
|||
"""
|
||||
----------------
|
||||
|
||||
## Advanced use cases
|
||||
## Read and write values: the `bind` property
|
||||
|
||||
### `visible` & `enabled` expression evaluation
|
||||
! Config panels only
|
||||
|
||||
Sometimes we may want to conditionaly display a message or prompt for a value, for this we have the `visible` prop.
|
||||
And we may want to allow a user to trigger an action only if some condition are met, for this we have the `enabled` prop.
|
||||
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.
|
||||
|
||||
Expressions are evaluated against a context containing previous values of the current section's options. This quite limited current design exists because on the web-admin or on the CLI we cannot guarantee that a value will be present in the form if the user queried only a single panel/section/option.
|
||||
In the case of an action, the user will be shown or asked for each of the options of the section in which the button is present.
|
||||
|
||||
The expression has to be written in javascript (this has been designed for the web-admin first and is converted to python on the fly on the cli).
|
||||
|
||||
Available operators are: `==`, `!=`, `>`, `>=`, `<`, `<=`, `!`, `&&`, `||`, `+`, `-`, `*`, `/`, `%` and `match()`.
|
||||
|
||||
##### Examples
|
||||
|
||||
```toml
|
||||
# simple "my_option_id" is thruthy/falsy
|
||||
visible = "my_option_id"
|
||||
visible = "!my_option_id"
|
||||
# misc
|
||||
visible = "my_value >= 10"
|
||||
visible = "-(my_value + 1) < 0"
|
||||
visible = "!!my_value || my_other_value"
|
||||
```
|
||||
For a more complete set of examples, [check the tests at the end of the file](https://github.com/YunoHost/yunohost/blob/dev/src/tests/test_questions.py).
|
||||
|
||||
##### match()
|
||||
|
||||
For more complex evaluation we can use regex matching.
|
||||
|
||||
```toml
|
||||
[my_string]
|
||||
default = "Lorem ipsum dolor et si qua met!"
|
||||
|
||||
[my_boolean]
|
||||
type = "boolean"
|
||||
visible = "my_string && match(my_string, '^Lorem [ia]psumE?')"
|
||||
```
|
||||
|
||||
Match the content of a file.
|
||||
|
||||
```toml
|
||||
[my_file]
|
||||
type = "file"
|
||||
accept = ".txt"
|
||||
bind = "/etc/random/lorem.txt"
|
||||
|
||||
[my_boolean]
|
||||
type = "boolean"
|
||||
visible = "my_file && match(my_file, '^Lorem [ia]psumE?')"
|
||||
```
|
||||
|
||||
with a file with content like:
|
||||
```txt
|
||||
Lorem ipsum dolor et si qua met!
|
||||
```
|
||||
|
||||
|
||||
### `bind`
|
||||
|
||||
Config panels only
|
||||
|
||||
`bind` allows us to alter the generic behavior of option's values which is: get from and set in the app `settings.yml`.
|
||||
`bind` allows us to alter the default behavior of applying option's values, which is: get from and set in the app `settings.yml`.
|
||||
|
||||
We can:
|
||||
- alter the source the value comes from with getters or binds to file.
|
||||
- alter the destination with setters or binds to file.
|
||||
- alter the source the value comes from wit binds to file or custom getters.
|
||||
- alter the destination with binds to file or settings.
|
||||
- parse/validate the value before destination with validators
|
||||
|
||||
----------------
|
||||
IMPORTANT: with the exception of `bind = "null"` options, options ids should almost **always** correspond to an app setting initialized / reused during install/upgrade.
|
||||
! IMPORTANT: with the exception of `bind = "null"` options, options ids should almost **always** correspond to an app setting initialized / reused during install/upgrade.
|
||||
Not doing so may result in inconsistencies between the config panel mechanism and the use of ynh_add_config
|
||||
|
||||
----------------
|
||||
|
||||
##### bind to file
|
||||
### Read / write into a var of a configuration file
|
||||
|
||||
Settings usually correspond to key/values in actual app configurations. Hence, a more useful mode is to have `bind = ":FILENAME"` with a colon `:` before. In that case, YunoHost will automagically find a line with `KEY=VALUE` in `FILENAME` (with the adequate separator between `KEY` and `VALUE`).
|
||||
|
||||
YunoHost will then use this value for the read/get operation. During write/set operations, YunoHost will overwrite the value in **both** FILENAME and in the app's settings.yml
|
||||
|
||||
Configuration file format supported: `yaml`, `toml`, `json`, `ini`, `env`, `php`, `python`.
|
||||
The feature probably works with others formats, but should be tested carefully.
|
||||
|
||||
Note that this feature only works with relatively simple cases such as `KEY: VALUE`, but won't properly work with complex data structures like multiline array/lists or dictionnaries.
|
||||
It also doesn't work with XML format, custom config function call, php define(), …
|
||||
If you need to save complex/multiline content in a configuration variable, you should do it via a specific getter/setter.
|
||||
|
||||
```toml
|
||||
[panel.section.config_value]
|
||||
# Do not use `file` for this since we only want to insert/save a value
|
||||
type = "string"
|
||||
bind = ":__FINALPATH__/config.ini"
|
||||
default = ""
|
||||
```
|
||||
|
||||
By default, `bind = ":FILENAME"` will use the option id as `KEY` but the option id may sometime not be the exact same `KEY` name in the configuration file.
|
||||
For example, [In pepettes app](https://github.com/YunoHost-Apps/pepettes_ynh/blob/5cc2d3ffd6529cc7356ff93af92dbb6785c3ab9a/conf/settings.py##L11), the python variable is `name` and not `project_name`. In that case, the key name can be specified before the colon `:`.
|
||||
|
||||
```toml
|
||||
[panel.section.project_name]
|
||||
bind = "name:__FINALPATH__/config.ini"
|
||||
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```toml
|
||||
bind = "importExportRateLimiting>max:__INSTALL_DIR__/conf.json"
|
||||
```
|
||||
|
||||
### Read / write an entire file
|
||||
|
||||
You can bind a `text` or directly a `file` to a specific file by using `bind = "FILEPATH`.
|
||||
|
||||
|
@ -225,142 +202,183 @@ bind = "__FINALPATH__/config.ini"
|
|||
default = "key: 'value'"
|
||||
```
|
||||
|
||||
##### bind a value inside a file
|
||||
## Advanced use cases
|
||||
|
||||
Settings usually correspond to key/values in actual app configurations. Hence, a more useful mode is to have `bind = ":FILENAME"` with a colon `:` before. In that case, YunoHost will automagically find a line with `KEY=VALUE` in `FILENAME` (with the adequate separator between `KEY` and `VALUE`).
|
||||
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
|
||||
|
||||
YunoHost will then use this value for the read/get operation. During write/set operations, YunoHost will overwrite the value in **both** FILENAME and in the app's settings.yml
|
||||
For all of those use cases, there are the specific getter or setter mechanism for an option!
|
||||
|
||||
Configuration file format supported: `yaml`, `toml`, `json`, `ini`, `env`, `php`, `python`.
|
||||
The feature probably works with others formats, but should be tested carefully.
|
||||
To create specific getter/setter, you first need to create a `config` script inside the `scripts` directory
|
||||
|
||||
Note that this feature only works with relatively simple cases such as `KEY: VALUE`, but won't properly work with complex data structures like multilin array/lists or dictionnaries.
|
||||
It also doesn't work with XML format, custom config function call, php define(), …
|
||||
`scripts/config`
|
||||
```bash
|
||||
#!/bin/bash
|
||||
source /usr/share/yunohost/helpers
|
||||
|
||||
ynh_abort_if_errors
|
||||
|
||||
```toml
|
||||
[panel.section.config_value]
|
||||
# Do not use `file` for this since we only want to insert/save a value
|
||||
type = "string"
|
||||
bind = ":__FINALPATH__/config.ini"
|
||||
default = ""
|
||||
# Put your getter, setter, validator or action here
|
||||
|
||||
# Keep this last line
|
||||
ynh_app_config_run $1
|
||||
```
|
||||
|
||||
By default, `bind = ":FILENAME"` will use the option id as `KEY` but the option id may sometime not be the exact same `KEY` name in the configuration file.
|
||||
For example, [In pepettes app](https://github.com/YunoHost-Apps/pepettes_ynh/blob/5cc2d3ffd6529cc7356ff93af92dbb6785c3ab9a/conf/settings.py##L11), the python variable is `name` and not `project_name`. In that case, the key name can be specified before the colon `:`.
|
||||
|
||||
```toml
|
||||
[panel.section.project_name]
|
||||
bind = "name:__FINALPATH__/config.ini"
|
||||
```
|
||||
|
||||
##### Getters
|
||||
### Getters
|
||||
|
||||
Define an option's custom getter in a bash script `script/config`.
|
||||
It has to be named after an option's id prepended by `get__`.
|
||||
It has to be named after an option's `id` prepended by `get__`.
|
||||
|
||||
To display a custom alert message for example. We setup a base option in `config_panel.toml`.
|
||||
The function should returns one of these two 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 option (like the `style` of an `alert`, the list of `choices` of a `select`, etc.)
|
||||
|
||||
```toml
|
||||
[panel.section.alert]
|
||||
type = "alert"
|
||||
# bind to "null" to inform there's something in `scripts/config`
|
||||
bind = "null"
|
||||
# `ask` & `style` will be injected by a custom getter
|
||||
|
||||
[details summary="<i>Basic example : Get the login inside the first line of a file </i>" class="helper-card-subtitle text-muted"]
|
||||
scripts/config
|
||||
```bash
|
||||
get__login_user() {
|
||||
if [ -s /etc/openvpn/keys/credentials ]
|
||||
then
|
||||
echo "$(sed -n 1p /etc/openvpn/keys/credentials)"
|
||||
else
|
||||
echo ""
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
Then add a custom getter that output yaml, every properties defined here will override any property previously declared.
|
||||
config_panel.toml
|
||||
```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
|
||||
```bash
|
||||
get__alert() {
|
||||
if [ "$whatever" ]; then
|
||||
cat << EOF
|
||||
get__plugins() {
|
||||
echo "choices: [$(ls $install_dir/plugins/ | tr '\n' ',')]"
|
||||
}
|
||||
```
|
||||
|
||||
config_panel.toml
|
||||
```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
|
||||
```bash
|
||||
get__status() {
|
||||
if [ -f "/sys/class/net/tun0/operstate" ] && [ "$(cat /sys/class/net/tun0/operstate)" == "up" ]
|
||||
then
|
||||
cat << EOF
|
||||
style: success
|
||||
ask: Your VPN is running :)
|
||||
ask:
|
||||
en: Your VPN is running :)
|
||||
EOF
|
||||
else
|
||||
cat << EOF
|
||||
cat << EOF
|
||||
style: danger
|
||||
ask: Your VPN is down
|
||||
ask:
|
||||
en: Your VPN is down
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
Or to inject a custom value:
|
||||
|
||||
config_panel.toml
|
||||
```toml
|
||||
[panel.section.my_hidden_value]
|
||||
type = "number"
|
||||
bind = "null"
|
||||
# option will act as an hidden variable that can be used in context evaluation
|
||||
# (ie: `visible` or `enabled`)
|
||||
readonly = true
|
||||
visible = false
|
||||
# `default` injected by a custom getter
|
||||
[main.cube.status]
|
||||
ask = "Custom getter alert"
|
||||
type = "alert"
|
||||
style = "info"
|
||||
bind = "null" # no behaviour on
|
||||
```
|
||||
[/details]
|
||||
|
||||
```bash
|
||||
get__my_hidden_value() {
|
||||
if [ "$whatever" ]; then
|
||||
# if only a value is needed
|
||||
echo "10"
|
||||
else
|
||||
# or if we need to override some other props
|
||||
# (use `default` or `value` to inject the value)
|
||||
cat << EOF
|
||||
ask: Here's a number
|
||||
visible: true
|
||||
default: 0
|
||||
EOF
|
||||
fi
|
||||
}
|
||||
```
|
||||
|
||||
##### Setters
|
||||
### Setters
|
||||
|
||||
Define an option's custom setter in a bash script `script/config`.
|
||||
It has to be named after an option's id prepended by `set__`.
|
||||
|
||||
```toml
|
||||
[panel.section.my_value]
|
||||
type = "string"
|
||||
bind = "null"
|
||||
ask = "gimme complex string"
|
||||
```
|
||||
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
|
||||
```bash
|
||||
set__my_value() {
|
||||
if [ -n "$my_value" ]; then
|
||||
# split the string into multiple elements or idk
|
||||
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
|
||||
# To save the value or modified value as a setting:
|
||||
ynh_app_setting_set --app=$app --key=my_value --value="$my_value"
|
||||
}
|
||||
```
|
||||
|
||||
##### Validators
|
||||
config_panel.toml
|
||||
```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
|
||||
```toml
|
||||
pattern.regexp = '^.+@.+$'
|
||||
pattern.error = 'An email is required for this field'
|
||||
```
|
||||
|
||||
You can also restrict several types with a choices list.
|
||||
```toml
|
||||
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` |
|
||||
| `boolean` | `yes` `no` |
|
||||
|
||||
|
||||
If you need more control over validation, you can use custom validators.
|
||||
Define an option's custom validator in a bash script `script/config`.
|
||||
It has to be named after an option's id prepended by `validate__`.
|
||||
|
||||
Validators allows us to return custom error messages depending on the value.
|
||||
|
||||
```toml
|
||||
[panel.section.my_value]
|
||||
type = "string"
|
||||
bind = "null"
|
||||
ask = "Gimme a long string"
|
||||
default = "too short"
|
||||
```
|
||||
|
||||
```bash
|
||||
validate__my_value() {
|
||||
if [[ "${#my_value}" -lt 12 ]]; then echo 'Too short!'; fi
|
||||
validate__login_user() {
|
||||
if [[ "${#login_user}" -lt 4 ]]; then echo 'Too short user login'; fi
|
||||
}
|
||||
```
|
||||
|
||||
##### Actions
|
||||
### Actions
|
||||
|
||||
Define an option's action in a bash script `script/config`.
|
||||
It has to be named after a `button`'s id prepended by `run__`.
|
||||
|
@ -407,5 +425,61 @@ run__my_action() {
|
|||
git clone "$my_repo" "$my_repo_name"
|
||||
}
|
||||
```
|
||||
|
||||
### `visible` & `enabled` expression evaluation
|
||||
|
||||
Sometimes we may want to conditionaly display a message or prompt for a value, for this we have the `visible` prop.
|
||||
And we may want to allow a user to trigger an action only if some condition are met, for this we have the `enabled` prop.
|
||||
|
||||
Expressions are evaluated against a context containing previous values of the current section's options. This quite limited current design exists because on the web-admin or on the CLI we cannot guarantee that a value will be present in the form if the user queried only a single panel/section/option.
|
||||
In the case of an action, the user will be shown or asked for each of the options of the section in which the button is present.
|
||||
|
||||
The expression has to be written in javascript (this has been designed for the web-admin first and is converted to python on the fly on the cli).
|
||||
|
||||
Available operators are: `==`, `!=`, `>`, `>=`, `<`, `<=`, `!`, `&&`, `||`, `+`, `-`, `*`, `/`, `%` and `match()`.
|
||||
|
||||
#### Examples
|
||||
|
||||
```toml
|
||||
# simple "my_option_id" is thruthy/falsy
|
||||
visible = "my_option_id"
|
||||
visible = "!my_option_id"
|
||||
# misc
|
||||
visible = "my_value >= 10"
|
||||
visible = "-(my_value + 1) < 0"
|
||||
visible = "!!my_value || my_other_value"
|
||||
```
|
||||
For a more complete set of examples, [check the tests at the end of the file](https://github.com/YunoHost/yunohost/blob/dev/src/tests/test_questions.py).
|
||||
|
||||
#### match()
|
||||
|
||||
For more complex evaluation we can use regex matching.
|
||||
|
||||
```toml
|
||||
[my_string]
|
||||
default = "Lorem ipsum dolor et si qua met!"
|
||||
|
||||
[my_boolean]
|
||||
type = "boolean"
|
||||
visible = "my_string && match(my_string, '^Lorem [ia]psumE?')"
|
||||
```
|
||||
|
||||
Match the content of a file.
|
||||
|
||||
```toml
|
||||
[my_file]
|
||||
type = "file"
|
||||
accept = ".txt"
|
||||
bind = "/etc/random/lorem.txt"
|
||||
|
||||
[my_boolean]
|
||||
type = "boolean"
|
||||
visible = "my_file && match(my_file, '^Lorem [ia]psumE?')"
|
||||
```
|
||||
|
||||
with a file with content like:
|
||||
```txt
|
||||
Lorem ipsum dolor et si qua met!
|
||||
```
|
||||
"""
|
||||
)
|
||||
|
|
|
@ -215,17 +215,36 @@ class PanelModel(ContainerModel):
|
|||
|
||||
class ConfigPanelModel(BaseModel):
|
||||
"""
|
||||
Configuration panels are descriptive format in TOML to bind settings to form items so that a user can alter some of the app's configuration without manually editing files from the command line.
|
||||
Configuration panels allows instances adminitrators to manage some parameters or runs some actions for which the app's 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 also be used as interface generator to extend quickly capabilities of YunoHost (e.g. VPN Client, Hotspost, Borg, etc.).
|
||||
|
||||
From a packager perspective, this `config_panel.toml` is coupled to the `scripts/config` script, which may be used to define custom getters/setters. However, most use cases should be covered automagically by the core, thus it may not be necessary to define a scripts/config at all!
|
||||
|
||||
! IMPORTANT: 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.
|
||||
|
||||
Config panels are structured as a series of panels (that renders as tabs in the web-admin) that contains a series of sections that contains options.
|
||||
Options can be directly binded to settings, or captured by custom bash setters/getter, `button` Options can trigger "actions" (e.g. custom bash functions).
|
||||
### 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 `scripts/config` to define custom getters/setters/validators/actions. However, most use cases should be covered automagically by the core, thus it may not be necessary to define a `scripts/config` at all!
|
||||
|
||||
- [Learn more about Options](/dev/forms) in their dedicated doc page as those are also used in app install forms.
|
||||
- [Check the basic toml example](https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example) and the [basic `scripts/config` example](https://github.com/YunoHost/example_ynh/blob/master/scripts/config)
|
||||
The `config_panel.toml` file describes one or several panels, containing some sections, containing some options generally binded to a params in a configuration file.
|
||||
|
||||
### Options 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
|
||||
```toml
|
||||
[manual.vpn.server_ip]
|
||||
[advanced.dns.server_ip]
|
||||
```
|
||||
Indeed the real variable name is server_ip and here you have a conflict.
|
||||
|
||||
### Options
|
||||
|
||||
[Learn more about Options](/dev/forms) in their dedicated doc page as those are also used in app install forms and core config panels.
|
||||
|
||||
### YunoHost community examples
|
||||
- [Check the basic example at the end of this doc](#basic-example)
|
||||
- [Check the example_ynh app toml](https://github.com/YunoHost/example_ynh/blob/master/config_panel.toml.example) and the [basic `scripts/config` example](https://github.com/YunoHost/example_ynh/blob/master/scripts/config)
|
||||
- [Check config panels of other apps](https://grep.app/search?q=version&filter[repo.pattern][0]=YunoHost-Apps&filter[lang][0]=TOML)
|
||||
- [Check `scripts/config` of other apps](https://grep.app/search?q=ynh_app_config_apply&filter[repo.pattern][0]=YunoHost-Apps&filter[lang][0]=Shell)
|
||||
|
||||
|
|
|
@ -374,8 +374,9 @@ class BaseOption(BaseModel):
|
|||
- if the path starts with `:`, the value be saved as its id's variable/property counterpart
|
||||
- this only works for first level variables/properties and simple types (no array)
|
||||
- else the value will be stored as the whole content of the file
|
||||
- you can use `__FINALPATH__` in your path to point to dynamic install paths
|
||||
- you can use `__FINALPATH__` or `__INSTALL_DIR__` in your path to point to dynamic install paths
|
||||
- FIXME are other global variables accessible?
|
||||
- [refer to `bind` doc for explaination and examples](#read-and-write-values-the)
|
||||
"""
|
||||
|
||||
type: OptionType
|
||||
|
|
Loading…
Add table
Reference in a new issue