configpanel: update _ask

This commit is contained in:
axolotle 2023-04-18 20:13:01 +02:00
parent 2c35dcbb24
commit 7a60703ef5

View file

@ -19,7 +19,6 @@
import glob import glob
import os import os
import re import re
import urllib.parse
from collections import OrderedDict from collections import OrderedDict
from logging import getLogger from logging import getLogger
from typing import TYPE_CHECKING, Any, Literal, Sequence, Type, Union from typing import TYPE_CHECKING, Any, Literal, Sequence, Type, Union
@ -36,19 +35,19 @@ from yunohost.utils.form import (
BaseOption, BaseOption,
BaseReadonlyOption, BaseReadonlyOption,
FileOption, FileOption,
FormModel,
OptionsModel, OptionsModel,
OptionType, OptionType,
Translation, Translation,
ask_questions_and_parse_answers,
build_form, build_form,
evaluate_simple_js_expression, evaluate_simple_js_expression,
parse_prefilled_values, parse_prefilled_values,
prompt_or_validate_form,
) )
from yunohost.utils.i18n import _value_for_locale from yunohost.utils.i18n import _value_for_locale
if TYPE_CHECKING: if TYPE_CHECKING:
from pydantic.fields import ModelField from pydantic.fields import ModelField
from yunohost.utils.form import FormModel, Hooks
logger = getLogger("yunohost.configpanel") logger = getLogger("yunohost.configpanel")
@ -279,7 +278,8 @@ class ConfigPanel:
save_mode = "full" save_mode = "full"
filter_key: "FilterKey" = (None, None, None) filter_key: "FilterKey" = (None, None, None)
config: Union[ConfigPanelModel, None] = None config: Union[ConfigPanelModel, None] = None
form: Union[FormModel, None] = None form: Union["FormModel", None] = None
hooks: "Hooks" = {}
@classmethod @classmethod
def list(cls): def list(cls):
@ -602,7 +602,7 @@ class ConfigPanel:
def _get_config_panel( def _get_config_panel(
self, prevalidate: bool = False self, prevalidate: bool = False
) -> tuple[ConfigPanelModel, FormModel]: ) -> tuple[ConfigPanelModel, "FormModel"]:
raw_config = self._get_partial_raw_config() raw_config = self._get_partial_raw_config()
config = ConfigPanelModel(**raw_config) config = ConfigPanelModel(**raw_config)
config, raw_settings = self._get_partial_raw_settings_and_mutate_config(config) config, raw_settings = self._get_partial_raw_settings_and_mutate_config(config)
@ -623,58 +623,62 @@ class ConfigPanel:
return (config, settings) return (config, settings)
def _ask(self, action=None): def ask(
self,
config: ConfigPanelModel,
settings: "FormModel",
prefilled_answers: dict[str, Any] = {},
action_id: Union[str, None] = None,
hooks: "Hooks" = {},
) -> "FormModel":
# FIXME could be turned into a staticmethod
logger.debug("Ask unanswered question and prevalidate data") logger.debug("Ask unanswered question and prevalidate data")
if "i18n" in self.config: interactive = Moulinette.interface.type == "cli" and os.isatty(1)
for panel, section, option in self._iterate():
if "ask" not in option: if interactive:
option["ask"] = m18n.n(self.config["i18n"] + "_" + option["id"]) config.translate()
# auto add i18n help text if present in locales
if m18n.key_exists(self.config["i18n"] + "_" + option["id"] + "_help"): for panel in config.panels:
option["help"] = m18n.n( if interactive:
self.config["i18n"] + "_" + option["id"] + "_help" Moulinette.display(
colorize(f"\n{'='*40}\n>>>> {panel.name}\n{'='*40}", "purple")
) )
def display_header(message): # A section or option may only evaluate its conditions (`visible`
"""CLI panel/section header display""" # and `enabled`) with its panel's local context that is built
if Moulinette.interface.type == "cli" and self.filter_key.count(".") < 2: # prompt after prompt.
Moulinette.display(colorize(message, "purple")) # That means that a condition can only reference options of its
# own panel and options that are previously defined.
context: dict[str, Any] = {}
for panel, section, obj in self._iterate(["panel", "section"]): for section in panel.sections:
if ( if (
section action_id is None and section.is_action_section
and section.get("visible") ) or not section.is_visible(context):
and not evaluate_simple_js_expression( # FIXME useless?
section["visible"], context=self.future_values Moulinette.display("Skipping section '{panel.id}.{section.id}'")
)
):
continue continue
# Ugly hack to skip action section ... except when when explicitly running actions if interactive and section.name:
if not action: Moulinette.display(colorize(f"\n# {section.name}", "purple"))
if section and section["is_action_section"]:
continue
if panel == obj:
name = _value_for_locale(panel["name"])
display_header(f"\n{'='*40}\n>>>> {name}\n{'='*40}")
else:
name = _value_for_locale(section["name"])
if name:
display_header(f"\n# {name}")
elif section:
# filter action section options in case of multiple buttons # filter action section options in case of multiple buttons
section["options"] = [ options = [
option option
for option in section["options"] for option in section.options
if option.get("type", OptionType.string) != OptionType.button if option.type is not OptionType.button or option.id == action_id
or option["id"] == action
] ]
if panel == obj: settings = prompt_or_validate_form(
continue options,
settings,
prefilled_answers=prefilled_answers,
context=context,
hooks=hooks,
)
<<<<<<< HEAD
# Check and ask unanswered questions # Check and ask unanswered questions
prefilled_answers = self.args.copy() prefilled_answers = self.args.copy()
prefilled_answers.update(self.new_values) prefilled_answers.update(self.new_values)
@ -692,6 +696,9 @@ class ConfigPanel:
if not question.readonly and question.value is not None if not question.readonly and question.value is not None
} }
) )
=======
return settings
>>>>>>> be777b928 (configpanel: update _ask)
def _apply(self): def _apply(self):
logger.info("Saving the new configuration...") logger.info("Saving the new configuration...")