mirror of
https://github.com/blakeblackshear/frigate.git
synced 2026-03-30 20:04:54 +03:00
Some checks are pending
CI / AMD64 Build (push) Waiting to run
CI / ARM Build (push) Waiting to run
CI / Jetson Jetpack 6 (push) Waiting to run
CI / AMD64 Extra Build (push) Blocked by required conditions
CI / ARM Extra Build (push) Blocked by required conditions
CI / Synaptics Build (push) Blocked by required conditions
CI / Assemble and push default build (push) Blocked by required conditions
* add generation script a script to read yaml code blocks from docs markdown files and generate corresponding "Frigate UI" tab instructions based on the json schema, i18n, section configs (hidden fields), and nav mappings * first pass * components * add to gitignore * second pass * fix broken anchors * fixes * clean up tabs * version bump * tweaks * remove role mapping config from ui
131 lines
4.0 KiB
Python
131 lines
4.0 KiB
Python
"""Parse TypeScript section config files for hidden/advanced field info."""
|
|
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
SECTION_CONFIGS_DIR = (
|
|
Path(__file__).resolve().parents[3]
|
|
/ "web"
|
|
/ "src"
|
|
/ "components"
|
|
/ "config-form"
|
|
/ "section-configs"
|
|
)
|
|
|
|
|
|
def _extract_string_array(text: str, field_name: str) -> list[str]:
|
|
"""Extract a string array value from TypeScript object literal text."""
|
|
pattern = rf"{field_name}\s*:\s*\[(.*?)\]"
|
|
match = re.search(pattern, text, re.DOTALL)
|
|
if not match:
|
|
return []
|
|
content = match.group(1)
|
|
return re.findall(r'"([^"]*)"', content)
|
|
|
|
|
|
def _parse_section_file(filepath: Path) -> dict[str, Any]:
|
|
"""Parse a single section config .ts file."""
|
|
text = filepath.read_text()
|
|
|
|
# Extract base block
|
|
base_match = re.search(r"base\s*:\s*\{(.*?)\n \}", text, re.DOTALL)
|
|
base_text = base_match.group(1) if base_match else ""
|
|
|
|
# Extract global block
|
|
global_match = re.search(r"global\s*:\s*\{(.*?)\n \}", text, re.DOTALL)
|
|
global_text = global_match.group(1) if global_match else ""
|
|
|
|
# Extract camera block
|
|
camera_match = re.search(r"camera\s*:\s*\{(.*?)\n \}", text, re.DOTALL)
|
|
camera_text = camera_match.group(1) if camera_match else ""
|
|
|
|
result: dict[str, Any] = {
|
|
"fieldOrder": _extract_string_array(base_text, "fieldOrder"),
|
|
"hiddenFields": _extract_string_array(base_text, "hiddenFields"),
|
|
"advancedFields": _extract_string_array(base_text, "advancedFields"),
|
|
}
|
|
|
|
# Merge global-level hidden fields
|
|
global_hidden = _extract_string_array(global_text, "hiddenFields")
|
|
if global_hidden:
|
|
result["globalHiddenFields"] = global_hidden
|
|
|
|
# Merge camera-level hidden fields
|
|
camera_hidden = _extract_string_array(camera_text, "hiddenFields")
|
|
if camera_hidden:
|
|
result["cameraHiddenFields"] = camera_hidden
|
|
|
|
return result
|
|
|
|
|
|
def load_section_configs() -> dict[str, dict[str, Any]]:
|
|
"""Load all section configs from TypeScript files.
|
|
|
|
Returns:
|
|
Dict mapping section name to parsed config.
|
|
"""
|
|
# Read sectionConfigs.ts to get the mapping of section keys to filenames
|
|
registry_path = SECTION_CONFIGS_DIR.parent / "sectionConfigs.ts"
|
|
registry_text = registry_path.read_text()
|
|
|
|
configs: dict[str, dict[str, Any]] = {}
|
|
|
|
for ts_file in SECTION_CONFIGS_DIR.glob("*.ts"):
|
|
if ts_file.name == "types.ts":
|
|
continue
|
|
|
|
section_name = ts_file.stem
|
|
configs[section_name] = _parse_section_file(ts_file)
|
|
|
|
# Map section config keys from the registry (handles renames like
|
|
# "timestamp_style: timestampStyle")
|
|
key_map: dict[str, str] = {}
|
|
for match in re.finditer(
|
|
r"(\w+)(?:\s*:\s*\w+)?\s*,", registry_text[registry_text.find("{") :]
|
|
):
|
|
key = match.group(1)
|
|
key_map[key] = key
|
|
|
|
# Handle explicit key mappings like `timestamp_style: timestampStyle`
|
|
for match in re.finditer(r"(\w+)\s*:\s*(\w+)\s*,", registry_text):
|
|
key_map[match.group(1)] = match.group(2)
|
|
|
|
return configs
|
|
|
|
|
|
def get_hidden_fields(
|
|
configs: dict[str, dict[str, Any]],
|
|
section_key: str,
|
|
level: str = "global",
|
|
) -> set[str]:
|
|
"""Get the set of hidden fields for a section at a given level.
|
|
|
|
Args:
|
|
configs: Loaded section configs
|
|
section_key: Config section name (e.g., "record")
|
|
level: "global" or "camera"
|
|
|
|
Returns:
|
|
Set of hidden field paths (e.g., {"enabled_in_config", "sync_recordings"})
|
|
"""
|
|
config = configs.get(section_key, {})
|
|
hidden = set(config.get("hiddenFields", []))
|
|
|
|
if level == "global":
|
|
hidden.update(config.get("globalHiddenFields", []))
|
|
elif level == "camera":
|
|
hidden.update(config.get("cameraHiddenFields", []))
|
|
|
|
return hidden
|
|
|
|
|
|
def get_advanced_fields(
|
|
configs: dict[str, dict[str, Any]],
|
|
section_key: str,
|
|
) -> set[str]:
|
|
"""Get the set of advanced fields for a section."""
|
|
config = configs.get(section_key, {})
|
|
return set(config.get("advancedFields", []))
|