Refine Settings page
Quality Gate / gate (push) Failing after 47s

This commit is contained in:
Jim Lancaster
2026-08-24 17:08:09 -05:00
parent c0112c2714
commit c05c054b94
5 changed files with 102 additions and 31 deletions
+6 -1
View File
@@ -14,15 +14,20 @@ Settings manages installation-local registries, safe runtime .env settings, and
- The page title is **Settings**.
- Configuration surfaces are grouped as tabs:
- **Runtime Settings**
- **Document Types**
- **Person Roles**
- **Tags**
- **Prompts**
- **Home Page Text**
- **Runtime Settings**
- Runtime Settings exposes an allowlisted set of non-secret fields synchronized with `Settings` model fields except excluded secret/unsafe fields.
- Runtime Settings is rendered as a compact two-column editor (**Setting**, **Value**) in a centered, narrower responsive container.
- Runtime Settings persists changes to `.env`, validates by constructing a `Settings` instance, and reports validation failures through the shared UI error presenter.
- Runtime Settings changes require application restart to take effect.
- Runtime Settings includes an explicit "Other settings not shown here" markdown table listing:
- secrets (`OPENROUTER_API_KEY`, `DATABASE__PASSWORD`)
- high-risk database connection settings (`DATABASE__DRIVER`, `DATABASE__PATH`, `DATABASE__HOST`, `DATABASE__PORT`, `DATABASE__DATABASE`, `DATABASE__USER`)
and directs edits for those keys to `.env`.
- Document Types, Person Roles, and Tags support Add/Edit/Delete with existing guardrails.
- Prompts exposes only `transcribe_document.md` for editing and restore-from-backup.
- Home Page Text edits the same Markdown content rendered on `/homepage`.
+57 -30
View File
@@ -21,6 +21,7 @@ from transcription.ui.components.primitives import section_header_row
from transcription.ui.components.table.registry import render_registry_table
from transcription.ui.homepage_store import read_homepage_markdown
from transcription.ui.homepage_store import save_homepage_markdown
from transcription.ui.runtime_settings_store import HIDDEN_SETTINGS_CATEGORIES
from transcription.ui.runtime_settings_store import read_runtime_settings_snapshot
from transcription.ui.runtime_settings_store import save_runtime_settings
from transcription.ui.theme import page_header
@@ -502,12 +503,10 @@ def register_page(*, settings: Settings) -> None: # noqa: PLR0915
@ui.refreshable
async def render_runtime_settings() -> None:
with archival_card("Runtime Settings"):
ui.label("Edit non-secret .env settings. Secret fields are intentionally excluded.").classes(
"text-xs ui-text-muted"
)
ui.label("Changes are persisted to .env and apply after restart.").classes(
"text-xs ui-text-muted mb-3"
)
ui.label(
"Edit non-secret .env settings. Secret fields are intentionally excluded. "
"Changes are persisted to .env and apply after restart."
).classes("text-xs ui-text-muted mb-3")
snapshot_outcome = await run_ui_action(
operation="settings.runtime.read",
title="Runtime settings unavailable",
@@ -517,27 +516,55 @@ def register_page(*, settings: Settings) -> None: # noqa: PLR0915
return
snapshot = snapshot_outcome.value
field_controls: dict[str, Any] = {}
for field in snapshot.fields:
with ui.column().classes("w-full gap-1 py-2 ui-header-divider"):
ui.label(field.label).classes("text-sm font-semibold")
ui.label(field.description).classes("text-xs ui-text-muted")
if field.control == "bool":
control = ui.checkbox(field.env_key, value=bool(field.value))
elif field.control == "select":
control = (
ui.select(
list(field.options),
label=field.env_key,
value=str(field.value),
with ui.column().classes("w-full max-w-3xl mx-auto gap-0.5"):
with ui.row().classes("w-full items-center px-2 py-1 border-b ui-border-subtle"):
ui.label("Setting").classes("w-56 text-xs font-semibold ui-text-muted")
ui.label("Value").classes("text-xs font-semibold ui-text-muted")
for field in snapshot.fields:
with ui.row().classes("w-full items-start gap-3 px-2 py-1 border-b ui-border-subtle"):
with ui.column().classes("w-56 gap-0"):
ui.label(field.label).classes("text-xs font-semibold")
ui.label(f"{field.env_key} · {field.description}").classes(
"text-[11px] ui-text-muted"
)
.props("outlined")
.classes("w-full")
)
else:
control = (
ui.input(field.env_key, value=str(field.value)).props("outlined").classes("w-full")
)
field_controls[field.field_name] = control
with ui.column().classes("flex-1 min-w-0"):
if field.control == "bool":
control = ui.checkbox("", value=bool(field.value)).props("dense")
elif field.control == "select":
control = (
ui.select(
list(field.options),
label="",
value=str(field.value),
)
.props("outlined dense")
.classes("w-full")
)
else:
control = (
ui.input("", value=str(field.value))
.props("outlined dense")
.classes("w-full")
)
field_controls[field.field_name] = control
with ui.column().classes("w-full max-w-3xl mx-auto gap-2 mt-3"):
ui.label("Other settings not shown here").classes("text-sm font-semibold")
ui.label("Edit these directly in .env:").classes("text-xs ui-text-muted")
table_rows = [
f"| {category.title} | {', '.join(f'`{key}`' for key in category.env_keys)} |"
for category in HIDDEN_SETTINGS_CATEGORIES
]
ui.markdown(
"\n".join(
[
"| **Category** | **Settings** |",
"|---|---|",
*table_rows,
]
)
).classes("w-full text-xs")
async def save_runtime() -> None:
updates: dict[str, str | bool] = {}
@@ -561,16 +588,14 @@ def register_page(*, settings: Settings) -> None: # noqa: PLR0915
ui.button("Save runtime settings", icon="save", on_click=save_runtime).classes("ui-btn-primary")
with ui.tabs().classes("w-full") as tabs:
runtime_settings_tab = ui.tab("Runtime Settings")
document_types_tab = ui.tab("Document Types")
person_roles_tab = ui.tab("Person Roles")
tags_tab = ui.tab("Tags")
prompts_tab = ui.tab("Prompts")
home_page_text_tab = ui.tab("Home Page Text")
runtime_settings_tab = ui.tab("Runtime Settings")
with ui.tab_panels(tabs, value=runtime_settings_tab).classes("w-full"):
with ui.tab_panel(runtime_settings_tab):
await render_runtime_settings()
with ui.tab_panels(tabs, value=document_types_tab).classes("w-full"):
with ui.tab_panel(document_types_tab):
await render_document_types()
with ui.tab_panel(person_roles_tab):
@@ -581,6 +606,8 @@ def register_page(*, settings: Settings) -> None: # noqa: PLR0915
await render_prompts()
with ui.tab_panel(home_page_text_tab):
await render_home_page_text()
with ui.tab_panel(runtime_settings_tab):
await render_runtime_settings()
def _selected_table_row(table: Any) -> dict[str, Any] | None:
@@ -49,6 +49,15 @@ class RuntimeSettingDescriptor:
options: tuple[str, ...] = ()
@dataclass(frozen=True, slots=True)
class HiddenSettingsCategory:
"""Settings excluded from the UI editor and why they are excluded."""
title: str
reason: str
env_keys: tuple[str, ...]
SETTINGS_UI_EXCLUDED_FIELDS = frozenset(
{
"openrouter_api_key",
@@ -56,6 +65,26 @@ SETTINGS_UI_EXCLUDED_FIELDS = frozenset(
}
)
HIDDEN_SETTINGS_CATEGORIES: tuple[HiddenSettingsCategory, ...] = (
HiddenSettingsCategory(
title="Not safe to expose/edit as plain text in UI (secrets)",
reason="These values are credentials and must remain hidden from page rendering and client responses.",
env_keys=("OPENROUTER_API_KEY", "DATABASE__PASSWORD"),
),
HiddenSettingsCategory(
title="Non-secret but high-risk (can break runtime/connectivity; still editable with guardrails)",
reason="These values control database connectivity and can make the app unavailable if changed incorrectly.",
env_keys=(
"DATABASE__DRIVER",
"DATABASE__PATH",
"DATABASE__HOST",
"DATABASE__PORT",
"DATABASE__DATABASE",
"DATABASE__USER",
),
),
)
RUNTIME_SETTINGS_CATALOG: tuple[RuntimeSettingDescriptor, ...] = (
RuntimeSettingDescriptor("host", "HOST", "Host", "Server bind host.", "text"),
RuntimeSettingDescriptor("port", "PORT", "Port", "Server bind port.", "text"),
+1
View File
@@ -32,4 +32,5 @@ class TestPageRegistration:
assert "Tags" in settings_response.text
assert "Prompts" in settings_response.text
assert "Home Page Text" in settings_response.text
assert "Other settings not shown here" in settings_response.text
assert "README.md" not in settings_response.text
+9
View File
@@ -8,6 +8,7 @@ import pytest
from transcription.config import Settings
from transcription.errors import AppError
from transcription.ui.runtime_settings_store import HIDDEN_SETTINGS_CATEGORIES
from transcription.ui.runtime_settings_store import RUNTIME_SETTINGS_CATALOG
from transcription.ui.runtime_settings_store import SETTINGS_UI_EXCLUDED_FIELDS
from transcription.ui.runtime_settings_store import read_runtime_settings_snapshot
@@ -28,6 +29,14 @@ def test_runtime_settings_catalog_classifies_all_non_secret_settings_fields():
assert "openrouter_api_key" not in settings_catalog_field_names()
def test_hidden_settings_categories_list_secret_and_high_risk_env_keys():
hidden_keys = {key for category in HIDDEN_SETTINGS_CATEGORIES for key in category.env_keys}
assert "OPENROUTER_API_KEY" in hidden_keys
assert "DATABASE__PASSWORD" in hidden_keys
assert "DATABASE__DRIVER" in hidden_keys
assert "DATABASE__HOST" in hidden_keys
def test_runtime_settings_snapshot_includes_catalog_fields(tmp_path: Path):
settings = _settings_for_runtime_editing(tmp_path)