"""Config flow for Wall Panel.""" from __future__ import annotations import json import secrets from typing import Any import voluptuous as vol from homeassistant import config_entries from homeassistant.const import CONF_NAME from homeassistant.helpers.selector import TextSelector, TextSelectorConfig, TextSelectorType from .const import ( CONF_CONFIG, CONF_FRONTEND_URL_PATH, CONF_REQUIRE_ADMIN, CONF_SIDEBAR_ICON, CONF_SIDEBAR_TITLE, CONF_SYNC_TOKEN, DEFAULT_FRONTEND_URL_PATH, DEFAULT_SIDEBAR_ICON, DEFAULT_SIDEBAR_TITLE, DOMAIN, ) from .helpers import config_to_json, current_entry_config, normalize_config, parse_config_json def _schema(defaults: dict[str, Any]) -> vol.Schema: return vol.Schema({ vol.Optional(CONF_NAME, default=defaults.get(CONF_NAME, "Striker Panel")): str, vol.Optional(CONF_SIDEBAR_TITLE, default=defaults.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE)): str, vol.Optional(CONF_SIDEBAR_ICON, default=defaults.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON)): str, vol.Optional(CONF_FRONTEND_URL_PATH, default=defaults.get(CONF_FRONTEND_URL_PATH, DEFAULT_FRONTEND_URL_PATH)): str, vol.Optional(CONF_REQUIRE_ADMIN, default=bool(defaults.get(CONF_REQUIRE_ADMIN, False))): bool, vol.Optional( CONF_CONFIG, default=defaults.get(CONF_CONFIG, config_to_json(normalize_config({}))), ): TextSelector(TextSelectorConfig(multiline=True, type=TextSelectorType.TEXT)), }) class WallPanelConfigFlow(config_entries.ConfigFlow, domain=DOMAIN): """Handle a config flow for Wall Panel.""" VERSION = 1 async def async_step_user(self, user_input: dict[str, Any] | None = None): errors: dict[str, str] = {} if self._async_current_entries(): return self.async_abort(reason="single_instance_allowed") if user_input is not None: try: config = parse_config_json(user_input[CONF_CONFIG]) except (json.JSONDecodeError, ValueError): errors[CONF_CONFIG] = "invalid_json" else: data = { CONF_NAME: user_input.get(CONF_NAME, "Striker Panel"), CONF_SIDEBAR_TITLE: str(user_input.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE) or DEFAULT_SIDEBAR_TITLE), CONF_SIDEBAR_ICON: str(user_input.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON) or DEFAULT_SIDEBAR_ICON), CONF_FRONTEND_URL_PATH: str(user_input.get(CONF_FRONTEND_URL_PATH, DEFAULT_FRONTEND_URL_PATH) or DEFAULT_FRONTEND_URL_PATH), CONF_REQUIRE_ADMIN: bool(user_input.get(CONF_REQUIRE_ADMIN, False)), CONF_SYNC_TOKEN: secrets.token_urlsafe(24), CONF_CONFIG: config, } await self.async_set_unique_id(DOMAIN) self._abort_if_unique_id_configured() return self.async_create_entry(title=data[CONF_SIDEBAR_TITLE], data={}, options=data) defaults = { CONF_NAME: "Striker Panel", CONF_SIDEBAR_TITLE: DEFAULT_SIDEBAR_TITLE, CONF_SIDEBAR_ICON: DEFAULT_SIDEBAR_ICON, CONF_FRONTEND_URL_PATH: DEFAULT_FRONTEND_URL_PATH, CONF_REQUIRE_ADMIN: False, CONF_CONFIG: config_to_json(normalize_config({})), } return self.async_show_form(step_id="user", data_schema=_schema(defaults), errors=errors) async def async_step_import(self, user_input: dict[str, Any]): return await self.async_step_user(user_input) class WallPanelOptionsFlow(config_entries.OptionsFlow): """Handle options for Wall Panel.""" def __init__(self, config_entry): self.config_entry = config_entry async def async_step_init(self, user_input: dict[str, Any] | None = None): errors: dict[str, str] = {} if user_input is not None: try: config = parse_config_json(user_input[CONF_CONFIG]) except (json.JSONDecodeError, ValueError): errors[CONF_CONFIG] = "invalid_json" else: data = dict(self.config_entry.options) data.update({ CONF_NAME: user_input.get(CONF_NAME, data.get(CONF_NAME, "Striker Panel")), CONF_SIDEBAR_TITLE: str(user_input.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE) or DEFAULT_SIDEBAR_TITLE), CONF_SIDEBAR_ICON: str(user_input.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON) or DEFAULT_SIDEBAR_ICON), CONF_FRONTEND_URL_PATH: str(user_input.get(CONF_FRONTEND_URL_PATH, DEFAULT_FRONTEND_URL_PATH) or DEFAULT_FRONTEND_URL_PATH), CONF_REQUIRE_ADMIN: bool(user_input.get(CONF_REQUIRE_ADMIN, False)), CONF_SYNC_TOKEN: data.get(CONF_SYNC_TOKEN, secrets.token_urlsafe(24)), CONF_CONFIG: config, }) return self.async_create_entry(title="", data=data) defaults = { CONF_NAME: self.config_entry.options.get(CONF_NAME, "Striker Panel"), CONF_SIDEBAR_TITLE: self.config_entry.options.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE), CONF_SIDEBAR_ICON: self.config_entry.options.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON), CONF_FRONTEND_URL_PATH: self.config_entry.options.get(CONF_FRONTEND_URL_PATH, DEFAULT_FRONTEND_URL_PATH), CONF_REQUIRE_ADMIN: self.config_entry.options.get(CONF_REQUIRE_ADMIN, False), CONF_CONFIG: config_to_json(current_entry_config(self.config_entry)), } return self.async_show_form(step_id="init", data_schema=_schema(defaults), errors=errors) def async_get_options_flow(config_entry): return WallPanelOptionsFlow(config_entry)