Recursos¶
Un recurso agrupa listado, formularios, infolist y relaciones en pantallas CUS generadas automáticamente.
Cuándo usar ResourceBuilder¶
- Necesitas CRUD o listado administrativo estándar.
- Quieres manifest, dashboards y forms sin escribir JSON a mano.
- El módulo vive dentro de un panel existente (
panel,accounting, etc.).
Deprecado
register_dashboards + ui/dashboards/*.json sigue funcionando para pantallas muy custom, pero no genera forms ni validación integrada. En plugins nuevos usa register_resources.
Registro¶
from cortex_framework.ui import ResourceBuilder, register_resource
from cortex_framework.ui.registry import ResourceRegistry
def register_resources(registry: ResourceRegistry) -> None:
def configure(builder: ResourceBuilder) -> None:
(
builder.id("clients")
.title("Clientes")
.api_base("/api/v1/clients")
.list_path("/api/v1/clients/clients")
.module_path("clients")
.record_title_attribute("name")
.nav_group("catalog", nav_sort=20)
.pages(list=True, create=False, edit=True, view=True)
.table(lambda t: ...)
.form(lambda f: ...)
.infolist(lambda i: ...)
)
register_resource(registry, "panel", "clients", configure)
Parámetros de register_resource:
| Argumento | Significado |
|---|---|
panel_id | Panel donde aparece el módulo (panel, accounting, …) |
module_id | Id del plugin en navegación y rutas UI |
configure | Función que recibe ResourceBuilder |
Ejemplo completo: plugins/clients/cortex_plugin_clients/resources.py.
Pantallas generadas¶
Por defecto el builder crea dashboards:
| Pantalla | Dashboard id | Condición |
|---|---|---|
| Listado | {resourceId}-list | .pages(list=True) |
| Crear | {resourceId}-create | .pages(create=True) + .form() |
| Editar | {resourceId}-edit | .pages(edit=True) + .form() |
| Ver | {resourceId}-view | .pages(view=True) + .infolist() |
API del ResourceBuilder¶
| Método | Descripción |
|---|---|
.id(str) | Id del recurso y prefijo de dashboards |
.title(str) | Título en navegación |
.api_base(str) | Base REST del módulo |
.module_path(str) | Segmento de ruta UI bajo el panel |
.record_title_attribute(str) | Campo para título de registro (búsqueda global) |
.nav_group(str, nav_sort=1000) | Grupo y orden en sidebar |
.pages(list, create, edit, view) | Páginas habilitadas |
.list_path(str) | Endpoint del listado |
.create_path(str) | Endpoint POST de creación |
.search_path(str) | Endpoint de búsqueda global |
.table(fn) | Configura TableBuilder |
.form(fn) | Configura FormBuilder |
.infolist(fn) | Configura InfolistBuilder |
.relation(fn) | Añade RelationBuilder en edición |
Qué registra el framework¶
Al llamar register_resource, el framework:
- Valida manifest y dashboards CUS.
- Registra el módulo en
DashboardRegistry(panel_id,module_id). - Registra
FormDefinitionpor cada formulario generado. - Publica
ResourceDefinitionpara búsqueda en el panel.
Contrato con el shell¶
El shell resuelve:
GET /api/v1/panels/{panelId}/modules/{moduleId}/manifestGET /api/v1/ui/dashboards/{dashboardId}GET /api/v1/forms/{formId}
Tu plugin solo mantiene las rutas REST de datos y persistencia.
Errores frecuentes¶
| Problema | Solución |
|---|---|
| Pantalla create sin formulario | Añade .form() o desactiva create en .pages() |
/create abre detalle vacío | Declara pantalla path: "create" antes de :id, o usa ResourceBuilder |
| Acción CREATE sin pantalla | Si la tabla tiene .create(...), habilita .pages(create=True) + .form() |
| Rutas UI 404 | Revisa module_path y que el panel host exista |
| Form no encontrado | El formId lo genera el builder; no lo hardcodees sin revisar el emit |
| Títulos duplicados | Usa ResourceBuilder (emite hide_title=True) o emit_dashboard(..., hide_title=True) |
Siguiente paso¶
Ver ADR 012 — UI Kit.