So, had some time on my hands and saw this as a bit of a learning exercise. Below is the code you would need to be able to place your config excerpt above into config.yaml, create a webservice and therefore be able to consume this via hass.callWS.
To use in your HA environment (sorry if this is teaching you to suck eggs), create a directory called panel_nested under config/custom_components.
Create a file init.py with the below code
"""Panel Nested component."""
from __future__ import annotations
import logging
import voluptuous as vol
from homeassistant.components import websocket_api
from homeassistant.components.websocket_api import ActiveConnection, async_register_command
from homeassistant.core import HomeAssistant
from homeassistant.helpers import config_validation as cv
from homeassistant.helpers.typing import ConfigType
DOMAIN = "panel_nested"
MENU_DATA = "menu_data"
CONF_MENU_ENTRY = "menu_entry_name"
CONF_MENU_ITEMS = "items"
CONF_SUBMENU_NAME = "submenu_name"
CONF_ICON = "icon"
CONF_URL_PATH = "url_path"
_LOGGER = logging.getLogger(__name__)
MENU_ITEM_SCHEMA = vol.Schema(
{
vol.Required(CONF_SUBMENU_NAME): cv.string,
vol.Optional(CONF_ICON): cv.string,
vol.Required(CONF_URL_PATH): cv.string,
}
)
PLATFORM_SCHEMA = vol.Schema(
{
vol.Required(CONF_MENU_ENTRY): cv.string,
vol.Optional(CONF_ICON): cv.string,
vol.Required(CONF_MENU_ITEMS): vol.All(cv.ensure_list, [MENU_ITEM_SCHEMA]),
}
)
async def async_setup(hass: HomeAssistant, config: ConfigType) -> bool:
"""Set up the template integration."""
hass.data.setdefault(DOMAIN, {})
# Debug log for config data
_LOGGER.debug(config[DOMAIN])
# Store menu config data
hass.data[DOMAIN][MENU_DATA] = config[DOMAIN]
await register_webservice(hass)
return True
async def register_webservice(hass: HomeAssistant) -> None:
"""Add webservice endpoint"""
@websocket_api.websocket_command(
{
vol.Required("type"): f"{DOMAIN}/data",
}
)
@websocket_api.async_response
async def menu_data(
hass: HomeAssistant, connection: ActiveConnection, msg: dict # pylint: disable=unused-argument
) -> None:
output = hass.data[DOMAIN][MENU_DATA]
connection.send_result(msg["id"], output)
async_register_command(hass, menu_data)
Create a manifest.json file with the below code (you will need to modifiy document link and code owner if you put on your github.
{
"domain": "panel_nested",
"name": "Nested Menu",
"config_flow": false,
"documentation": "https://github.com/github_user/panel_nested",
"iot_class": "calculated",
"version": "v1.0.0",
"requirements": [],
"dependencies": [],
"codeowners": [
"@github_user"
]
}
You can then use from your frontend or test in postman etc. Output from postman when called using an extended copy of your config excerpt.
{
"id": 1,
"type": "result",
"success": true,
"result": [
{
"menu_entry_name": "Monitoring",
"icon": "mdi:icon",
"items": [
{
"submenu_name": "Chronograf",
"icon": "mdi:icon",
"url_path": "/url-for-chronograf-admin-panel"
},
{
"submenu_name": "InfluxDB",
"icon": "mdi:icon",
"url_path": "/url-for-influxdb-admin-app"
},
{
"submenu_name": "Grafana",
"icon": "mdi:icon",
"url_path": "/url-for-grafana-admin-dashboard-panel"
}
]
},
{
"menu_entry_name": "Editors",
"icon": "mdi:icon",
"items": [
{
"submenu_name": "Menu1",
"icon": "mdi:icon",
"url_path": "/menu1"
},
{
"submenu_name": "Menu2",
"icon": "mdi:icon",
"url_path": "/menu2"
},
{
"submenu_name": "Menu3",
"icon": "mdi:icon",
"url_path": "/menu3"
}
]
}
]
}