This commit is contained in:
Striker72rus 2026-03-25 16:47:18 +03:00
parent 4c6ba44dba
commit b5d3feb726
20 changed files with 56 additions and 33 deletions

View File

@ -455,6 +455,10 @@
url.searchParams.set(key, value); url.searchParams.set(key, value);
} }
}); });
const proxyToken = String(window.APP_BOOTSTRAP?.ui?.proxy_token || '').trim();
if (proxyToken && !url.searchParams.has('token')) {
url.searchParams.set('token', proxyToken);
}
return url.toString(); return url.toString();
} }

View File

@ -1,6 +1,6 @@
{ {
"app": { "app": {
"title": "Wall Panel", "title": "Striker Panel",
"poll_interval_ms": 5000, "poll_interval_ms": 5000,
"main_room_name": "Главная", "main_room_name": "Главная",
"main_room_icon": "mdi:home", "main_room_icon": "mdi:home",

View File

@ -30,7 +30,7 @@ from .helpers import config_to_json, normalize_config, parse_config_json
def _schema(defaults: dict[str, Any]) -> vol.Schema: def _schema(defaults: dict[str, Any]) -> vol.Schema:
return vol.Schema({ return vol.Schema({
vol.Optional(CONF_NAME, default=defaults.get(CONF_NAME, "Wall Panel")): str, vol.Optional(CONF_NAME, default=defaults.get(CONF_NAME, "Striker Panel")): str,
vol.Optional(CONF_PANEL_URL, default=defaults.get(CONF_PANEL_URL, DEFAULT_PANEL_URL)): str, vol.Optional(CONF_PANEL_URL, default=defaults.get(CONF_PANEL_URL, DEFAULT_PANEL_URL)): str,
vol.Optional(CONF_SIDEBAR_TITLE, default=defaults.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE)): 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_SIDEBAR_ICON, default=defaults.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON)): str,
@ -61,7 +61,7 @@ class WallPanelConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
errors[CONF_CONFIG] = "invalid_json" errors[CONF_CONFIG] = "invalid_json"
else: else:
data = { data = {
CONF_NAME: user_input.get(CONF_NAME, "Wall Panel"), CONF_NAME: user_input.get(CONF_NAME, "Striker Panel"),
CONF_PANEL_URL: str(user_input.get(CONF_PANEL_URL, "") or ""), CONF_PANEL_URL: str(user_input.get(CONF_PANEL_URL, "") or ""),
CONF_SIDEBAR_TITLE: str(user_input.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE) or DEFAULT_SIDEBAR_TITLE), 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_SIDEBAR_ICON: str(user_input.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON) or DEFAULT_SIDEBAR_ICON),
@ -75,7 +75,7 @@ class WallPanelConfigFlow(config_entries.ConfigFlow, domain=DOMAIN):
return self.async_create_entry(title=data[CONF_SIDEBAR_TITLE], data={}, options=data) return self.async_create_entry(title=data[CONF_SIDEBAR_TITLE], data={}, options=data)
defaults = { defaults = {
CONF_NAME: "Wall Panel", CONF_NAME: "Striker Panel",
CONF_PANEL_URL: DEFAULT_PANEL_URL, CONF_PANEL_URL: DEFAULT_PANEL_URL,
CONF_SIDEBAR_TITLE: DEFAULT_SIDEBAR_TITLE, CONF_SIDEBAR_TITLE: DEFAULT_SIDEBAR_TITLE,
CONF_SIDEBAR_ICON: DEFAULT_SIDEBAR_ICON, CONF_SIDEBAR_ICON: DEFAULT_SIDEBAR_ICON,
@ -106,7 +106,7 @@ class WallPanelOptionsFlow(config_entries.OptionsFlow):
else: else:
data = dict(self.config_entry.options) data = dict(self.config_entry.options)
data.update({ data.update({
CONF_NAME: user_input.get(CONF_NAME, data.get(CONF_NAME, "Wall Panel")), CONF_NAME: user_input.get(CONF_NAME, data.get(CONF_NAME, "Striker Panel")),
CONF_PANEL_URL: str(user_input.get(CONF_PANEL_URL, "") or ""), CONF_PANEL_URL: str(user_input.get(CONF_PANEL_URL, "") or ""),
CONF_SIDEBAR_TITLE: str(user_input.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE) or DEFAULT_SIDEBAR_TITLE), 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_SIDEBAR_ICON: str(user_input.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON) or DEFAULT_SIDEBAR_ICON),
@ -118,7 +118,7 @@ class WallPanelOptionsFlow(config_entries.OptionsFlow):
return self.async_create_entry(title="", data=data) return self.async_create_entry(title="", data=data)
defaults = { defaults = {
CONF_NAME: self.config_entry.options.get(CONF_NAME, "Wall Panel"), CONF_NAME: self.config_entry.options.get(CONF_NAME, "Striker Panel"),
CONF_PANEL_URL: self.config_entry.options.get(CONF_PANEL_URL, DEFAULT_PANEL_URL), CONF_PANEL_URL: self.config_entry.options.get(CONF_PANEL_URL, DEFAULT_PANEL_URL),
CONF_SIDEBAR_TITLE: self.config_entry.options.get(CONF_SIDEBAR_TITLE, DEFAULT_SIDEBAR_TITLE), 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_SIDEBAR_ICON: self.config_entry.options.get(CONF_SIDEBAR_ICON, DEFAULT_SIDEBAR_ICON),

View File

@ -10,8 +10,8 @@ CONF_SIDEBAR_ICON = "sidebar_icon"
CONF_FRONTEND_URL_PATH = "frontend_url_path" CONF_FRONTEND_URL_PATH = "frontend_url_path"
CONF_REQUIRE_ADMIN = "require_admin" CONF_REQUIRE_ADMIN = "require_admin"
DEFAULT_NAME = "Wall Panel" DEFAULT_NAME = "Striker Panel"
DEFAULT_PANEL_URL = "" DEFAULT_PANEL_URL = ""
DEFAULT_SIDEBAR_TITLE = "Wall Panel" DEFAULT_SIDEBAR_TITLE = "Striker Panel"
DEFAULT_SIDEBAR_ICON = "mdi:view-dashboard" DEFAULT_SIDEBAR_ICON = "mdi:view-dashboard"
DEFAULT_FRONTEND_URL_PATH = "wall-panel" DEFAULT_FRONTEND_URL_PATH = "striker-panel"

View File

@ -2,6 +2,7 @@
from __future__ import annotations from __future__ import annotations
import time
from pathlib import Path from pathlib import Path
from homeassistant.components.frontend import async_register_built_in_panel from homeassistant.components.frontend import async_register_built_in_panel
@ -43,6 +44,7 @@ async def async_setup_frontend(hass: HomeAssistant, entry) -> str:
require_admin = bool(entry.options.get(CONF_REQUIRE_ADMIN, False)) require_admin = bool(entry.options.get(CONF_REQUIRE_ADMIN, False))
panel_url = str(entry.options.get(CONF_PANEL_URL, "") or "").strip() panel_url = str(entry.options.get(CONF_PANEL_URL, "") or "").strip()
sync_token = str(entry.options.get(CONF_SYNC_TOKEN, "") or "").strip() sync_token = str(entry.options.get(CONF_SYNC_TOKEN, "") or "").strip()
asset_version = str(int(time.time()))
async_register_built_in_panel( async_register_built_in_panel(
hass, hass,
@ -52,8 +54,8 @@ async def async_setup_frontend(hass: HomeAssistant, entry) -> str:
frontend_url_path=panel_url_path, frontend_url_path=panel_url_path,
config={ config={
"_panel_custom": { "_panel_custom": {
"name": "wall-panel-panel", "name": "striker-panel-panel",
"module_url": f"/api/{DOMAIN}/frontend/panel.js", "module_url": f"/api/{DOMAIN}/frontend/panel.js?v={asset_version}",
"embed_iframe": False, "embed_iframe": False,
"trust_external": False, "trust_external": False,
"config": { "config": {

View File

@ -81,7 +81,15 @@ class WallPanelPanel extends HTMLElement {
return ''; return '';
} }
return `/api/wall_panel/proxy/${encodeURIComponent(entryId)}/`; const token = String(payload.sync_token || '').trim();
const url = `/api/wall_panel/proxy/${encodeURIComponent(entryId)}/`;
if (!token) {
return url;
}
const proxyUrl = new URL(url, window.location.href);
proxyUrl.searchParams.set('token', token);
return proxyUrl.pathname + proxyUrl.search + proxyUrl.hash;
} }
_hasPanelUrl() { _hasPanelUrl() {
@ -191,7 +199,7 @@ class WallPanelPanel extends HTMLElement {
const panelUrl = this._resolveUrl(payload.panel_url || payload.ingress_url || ''); const panelUrl = this._resolveUrl(payload.panel_url || payload.ingress_url || '');
const configUrl = this._configUrl(); const configUrl = this._configUrl();
this._renderMessage( this._renderMessage(
'Waiting for Wall Panel', 'Waiting for Striker Panel',
panelUrl panelUrl
? 'Open this panel through Home Assistant after the add-on URL is configured.' ? 'Open this panel through Home Assistant after the add-on URL is configured.'
: 'Set the PHP panel URL in the integration options.', : 'Set the PHP panel URL in the integration options.',
@ -216,6 +224,6 @@ class WallPanelPanel extends HTMLElement {
} }
} }
if (!customElements.get('wall-panel-panel')) { if (!customElements.get('striker-panel-panel')) {
customElements.define('wall-panel-panel', WallPanelPanel); customElements.define('striker-panel-panel', WallPanelPanel);
} }

View File

@ -24,7 +24,7 @@ from .const import (
def default_config() -> dict[str, Any]: def default_config() -> dict[str, Any]:
return { return {
"app": { "app": {
"title": "Wall Panel", "title": "Striker Panel",
"poll_interval_ms": 5000, "poll_interval_ms": 5000,
"main_room_name": "Главная", "main_room_name": "Главная",
"main_room_icon": "mdi:home", "main_room_icon": "mdi:home",

View File

@ -1,8 +1,8 @@
{ {
"domain": "wall_panel", "domain": "wall_panel",
"name": "Wall Panel", "name": "Striker Panel",
"version": "1.0.0", "version": "1.0.0",
"documentation": "https://example.invalid/wall-panel", "documentation": "https://example.invalid/striker-panel",
"codeowners": [], "codeowners": [],
"config_flow": true, "config_flow": true,
"iot_class": "local_polling", "iot_class": "local_polling",

View File

@ -2,8 +2,8 @@
"config": { "config": {
"step": { "step": {
"user": { "user": {
"title": "Wall Panel", "title": "Striker Panel",
"description": "Connect Wall Panel to Home Assistant.", "description": "Connect Striker Panel to Home Assistant.",
"data": { "data": {
"name": "Name", "name": "Name",
"panel_url": "PHP panel URL", "panel_url": "PHP panel URL",

View File

@ -2,8 +2,8 @@
"config": { "config": {
"step": { "step": {
"user": { "user": {
"title": "Wall Panel", "title": "Striker Panel",
"description": "Connect Wall Panel to Home Assistant.", "description": "Connect Striker Panel to Home Assistant.",
"data": { "data": {
"name": "Name", "name": "Name",
"panel_url": "PHP panel URL", "panel_url": "PHP panel URL",

View File

@ -235,6 +235,9 @@ async def _handle_proxy_request(request: web.Request, entry_id: str, path: str,
entry = _entry_from_hass(hass, entry_id) entry = _entry_from_hass(hass, entry_id)
if entry is None: if entry is None:
return _response({"ok": False, "error": "Unknown entry"}, 404) return _response({"ok": False, "error": "Unknown entry"}, 404)
if not _authorized(entry, request):
_LOGGER.warning("Wall Panel proxy denied for %s: unauthorized", entry_id)
return _response({"ok": False, "error": "Unauthorized"}, 401)
base_url = str(entry.options.get(CONF_PANEL_URL, "") or "").strip() base_url = str(entry.options.get(CONF_PANEL_URL, "") or "").strip()
if not base_url: if not base_url:

View File

@ -27,6 +27,7 @@ $bootstrap['ui'] = [
'mode' => $runtimeMode, 'mode' => $runtimeMode,
'shell' => $embedMode ? 'embed' : 'standalone', 'shell' => $embedMode ? 'embed' : 'standalone',
'config_source' => app_remote_sync_enabled($config) ? 'ha' : 'file', 'config_source' => app_remote_sync_enabled($config) ? 'ha' : 'file',
'proxy_token' => trim((string)($_GET['token'] ?? '')),
]; ];
$appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); $appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
?> ?>

View File

@ -5,7 +5,7 @@ function app_default_config(): array
{ {
return [ return [
'app' => [ 'app' => [
'title' => 'Wall Panel', 'title' => 'Striker Panel',
'poll_interval_ms' => 5000, 'poll_interval_ms' => 5000,
'main_room_name' => 'Главная', 'main_room_name' => 'Главная',
'main_room_icon' => 'mdi:home', 'main_room_icon' => 'mdi:home',

View File

@ -1,3 +1,3 @@
name: Wall Panel Add-ons name: Striker Panel Add-ons
url: https://git.striker72rus.ru/PHP/wallpanell.git url: https://git.striker72rus.ru/PHP/wallpanell.git
maintainer: Striker72rus maintainer: Striker72rus

View File

@ -1,6 +1,6 @@
{ {
"active": false, "active": false,
"sensor_entity_id": "binary_sensor.barn_all_occupancy", "sensor_entity_id": "binary_sensor.barn_all_occupancy",
"opened_at": 1774444953, "opened_at": 1774445418,
"expires_at": null "expires_at": null
} }

View File

@ -455,6 +455,10 @@
url.searchParams.set(key, value); url.searchParams.set(key, value);
} }
}); });
const proxyToken = String(window.APP_BOOTSTRAP?.ui?.proxy_token || '').trim();
if (proxyToken && !url.searchParams.has('token')) {
url.searchParams.set('token', proxyToken);
}
return url.toString(); return url.toString();
} }

View File

@ -1,6 +1,6 @@
name: Wall Panel name: Striker Panel
description: Wall Panel PHP interface as a Home Assistant add-on description: Striker Panel PHP interface as a Home Assistant add-on
version: "1.0.22" version: "1.0.23"
slug: wall_panel slug: wall_panel
url: https://git.striker72rus.ru/PHP/wallpanell.git url: https://git.striker72rus.ru/PHP/wallpanell.git
init: false init: false
@ -15,14 +15,14 @@ ingress: true
ingress_panel: true ingress_panel: true
ingress_port: 8099 ingress_port: 8099
webui: "http://[HOST]:[PORT:8099]/" webui: "http://[HOST]:[PORT:8099]/"
panel_title: Wall Panel panel_title: Striker Panel
panel_icon: mdi:view-dashboard panel_icon: mdi:view-dashboard
hassio_api: true hassio_api: true
hassio_role: default hassio_role: default
ports: ports:
8099/tcp: 8099 8099/tcp: 8099
ports_description: ports_description:
8099/tcp: Wall Panel web UI 8099/tcp: Striker Panel web UI
map: map:
- type: homeassistant_config - type: homeassistant_config
read_only: false read_only: false
@ -30,7 +30,7 @@ map:
homeassistant_api: true homeassistant_api: true
options: options:
app: app:
title: Wall Panel title: Striker Panel
poll_interval_ms: 5000 poll_interval_ms: 5000
main_room_name: Главная main_room_name: Главная
main_room_icon: mdi:home main_room_icon: mdi:home

View File

@ -1,6 +1,6 @@
{ {
"app": { "app": {
"title": "Wall Panel", "title": "Striker Panel",
"poll_interval_ms": 5000, "poll_interval_ms": 5000,
"main_room_name": "Главная", "main_room_name": "Главная",
"main_room_icon": "mdi:home", "main_room_icon": "mdi:home",

View File

@ -27,6 +27,7 @@ $bootstrap['ui'] = [
'mode' => $runtimeMode, 'mode' => $runtimeMode,
'shell' => $embedMode ? 'embed' : 'standalone', 'shell' => $embedMode ? 'embed' : 'standalone',
'config_source' => app_remote_sync_enabled($config) ? 'ha' : 'file', 'config_source' => app_remote_sync_enabled($config) ? 'ha' : 'file',
'proxy_token' => trim((string)($_GET['token'] ?? '')),
]; ];
$appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8'); $appTitle = htmlspecialchars((string)($config['app']['title'] ?? 'Wall Panel'), ENT_QUOTES | ENT_SUBSTITUTE, 'UTF-8');
?> ?>

View File

@ -5,7 +5,7 @@ function app_default_config(): array
{ {
return [ return [
'app' => [ 'app' => [
'title' => 'Wall Panel', 'title' => 'Striker Panel',
'poll_interval_ms' => 5000, 'poll_interval_ms' => 5000,
'main_room_name' => 'Главная', 'main_room_name' => 'Главная',
'main_room_icon' => 'mdi:home', 'main_room_icon' => 'mdi:home',