Coverage for src / lexigram / admin / services / form_renderer.py: 39%
23 statements
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
« prev ^ index » next coverage.py v7.13.5, created at 2026-08-13 22:14 +0800
1"""Form Renderer Service for Lexigram Admin.
3Provides a unified interface for rendering schema-driven forms with
4built-in RBAC enforcement.
5"""
7from __future__ import annotations
9from typing import Any
11from lexigram.admin.forms.components import FormSchema, FormSchemaGenerator
12from lexigram.admin.ui.organisms.dynamic_form import DynamicForm
13from lexigram.di.decorators import inject
16@inject
17class FormRenderer:
18 """Service for rendering forms with RBAC integration.
20 Orchestrates schema generation, permission filtering, and
21 component instantiation.
22 """
24 def __init__(self, generator: FormSchemaGenerator) -> None:
25 self.generator = generator
27 def render_form(
28 self,
29 model: type | None = None,
30 schema: FormSchema | None = None,
31 user: Any = None,
32 resource_name: str = "unknown",
33 action: str = "",
34 method: str = "POST",
35 initial_data: dict[str, Any] | None = None,
36 submit_text: str = "Submit",
37 hx_post: str | None = None,
38 hx_target: str | None = None,
39 hx_swap: str = "outerHTML",
40 ) -> DynamicForm:
41 """Render a form for the given model/schema and user context.
43 Args:
44 model: Pydantic model class to generate schema from.
45 schema: Explicit FormSchema (overrides model).
46 user: Current user for RBAC filtering.
47 resource_name: Name of the resource for RBAC checks.
48 action: Form action URL.
49 method: HTTP method.
50 initial_data: Initial values for the form.
51 submit_text: Text for the submit button.
52 hx_post: HTMX post URL.
53 hx_target: HTMX target selector.
54 hx_swap: HTMX swap strategy.
56 Returns:
57 A DynamicForm component instance ready for rendering.
58 """
59 # 1. Resolve base schema
60 if schema:
61 base_schema = schema
62 elif model:
63 base_schema = self.generator.from_pydantic(model)
64 else:
65 base_schema = FormSchema()
67 # Update resource name in schema if provided
68 if resource_name != "unknown":
69 base_schema.resource_name = resource_name
71 # 2. Apply RBAC filtering if user is provided
72 form_schema = base_schema.filter_for_user(user) if user else base_schema # type: ignore[attr-defined]
74 # 3. Apply initial data as defaults if provided
75 if initial_data:
76 for field in form_schema.fields:
77 if field.name in initial_data:
78 field.default = initial_data[field.name]
80 # 4. Create and return the DynamicForm
81 return DynamicForm(
82 schema=form_schema,
83 action=action,
84 method=method,
85 submit_text=submit_text,
86 hx_post=hx_post,
87 hx_target=hx_target,
88 hx_swap=hx_swap,
89 )