Definición de vista basada en modelo
Id del esquema: model-driven-view@2
Esquema legible por máquina: model-driven-view.schema.json
Versión reemplazada: model-driven-view@1
(model-driven-view-v1.schema.json) sigue publicada
y registrada, de modo que una solución ya implementada con ella se sigue validando con el esquema
para el que se creó. La versión 2 solo añade propiedades opcionales —la tabla Forma de más
abajo es la lista actual—, así que toda definición v1 es también una definición v2 válida y no hay
que reescribir nada.
La representación canónica de una vista de las aplicaciones basadas en modelo (sección 6.7): una lista tabular de registros con sus columnas, filtros y ordenaciones.
Forma
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
logicalName | string | sí | Con el prefijo del editor, en snake_case en minúsculas. |
displayName | string | sí | Nombre legible de la vista. |
entity | string | sí | El nombre lógico de la entidad propietaria. |
description | string | no | La línea que se muestra bajo el título en la barra de título de la vista. |
icon | string | no | El icono que se muestra en la barra de título de la vista. |
viewType | string | no | Para qué sirve la vista: Public (predeterminado), Lookup, QuickFind, Associated, QuickView, Card, SeedData. |
seedDataKind | string | en una vista SeedData | Obligatorio en una vista SeedData y rechazado en cualquier otra: Configuration (filas que la solución necesita para funcionar; una importación siempre las trae, también a Producción) o Demonstration (filas de ejemplo; solo se importan cuando se marca Incluir datos de demostración, y nunca en Producción). Se incluye en el paquete como el kind del documento de datos iniciales. |
columns | array | sí | Nombres lógicos de los campos que se muestran como columnas. |
filters | array | no | Cláusulas de filtro planas (combinadas con AND): field, operator y (para los operadores con valor) value. |
filterGroup | object | no | Un árbol de filtros jerárquico AND/OR (al estilo de Búsqueda avanzada), combinado con filters mediante AND. |
sorts | array | no | Cláusulas de ordenación: field, descending. |
actions | array | no | Acciones diseñables de la barra de comandos. |
hierarchy | object | no | Presente cuando la vista se representa como un árbol en lugar de una cuadrícula. |
calendar | object | no | Presente cuando la vista se representa como un calendario en lugar de una cuadrícula. Nunca junto con hierarchy. |
columnProperties | array | no | Cómo se presentan las columnas individuales: encabezado, ancho, formato, alineación, control. Disperso. |
commandOverrides | array | no | Lo que esta vista cambia de los comandos que son propiedad de la plataforma. |
commandOrder | array | no | Una barra, un orden: comandos integrados y del creador intercalados, por id. |
rowSelection | boolean | no | Indica si las filas llevan una casilla de selección. true de forma predeterminada. |
Operadores: Equals, NotEquals, Contains, GreaterThan, LessThan, IsNull,
IsNotNull. Todos los campos a los que se hace referencia (columnas, filtros, condiciones de
grupos de filtros, ordenaciones) deben existir en la entidad.
viewType
El tipo de una vista indica qué superficie la lee. Una entidad puede tener a la vez una vista predeterminada de cada tipo, porque responden a preguntas distintas:
| Valor | Para qué sirve |
|---|---|
Public | La página de lista normal de la entidad. Es el valor predeterminado, y lo que es una definición sin viewType. |
Lookup | Las columnas que se muestran dentro del panel de resultados de un control de búsqueda; normalmente de dos a cuatro. |
QuickFind | Las columnas de búsqueda: las columnas con las que se compara una búsqueda escrita. Sus columns son el conjunto en el que se busca; sus filtros y ordenaciones no se leen. |
SeedData | Las filas y columnas que viajan con la solución (PF22). Nunca se muestra: una exportación de solución la ejecuta —sus filters deciden las filas y sus columns, los campos— y empaqueta el resultado como un documento seed-data@1, que una importación inserta o actualiza por id. Una tabla con varias usa la predeterminada o, si no la hay, la primera por nombre lógico. |
Associated | La subcuadrícula de registros relacionados. Reservado: todavía no hay nada que la represente. |
Un control de búsqueda que no nombra ninguna vista resuelve una automáticamente: la vista
Lookup predeterminada de la entidad de destino; si no la hay, su vista Public predeterminada
recortada a sus tres primeras columnas; y si tampoco, solo el campo principal de la entidad. Una
búsqueda sin vista QuickFind compara únicamente con el campo principal. Las columnas de búsqueda
deben ser campos de texto, ya que la comparación es un «contiene» que no distingue mayúsculas de
minúsculas.
calendar (una vista que se representa como calendario)
Una vista con un bloque calendar dibuja sus registros colocados en una hoja de día, semana o
mes —según dos de sus propios campos de fecha— en lugar de como una cuadrícula. Si falta, es la
cuadrícula, exactamente igual que con hierarchy, así que todas las vistas almacenadas siguen
siendo válidas. Una vista que incluye ambos bloques se rechaza: una vista se dibuja de una sola
manera.
Es una asignación, no un modelo de datos. No hay tabla de reservas ni tipo de cita: cualquier tabla que tenga una fecha puede disponerse en un calendario, y cuál de sus fechas significa «empieza» lo decide el creador.
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
start | string | sí | El campo de fecha y hora en el que se coloca un bloque. El único rol obligatorio: un registro sin inicio no puede colocarse en una hoja, así que no hay nada a lo que recurrir. Se admite un campo del sistema: created_at_utc dispone los registros según cuándo llegaron. |
end | string | no | El campo de fecha y hora en el que termina un bloque. La ausencia sirve para una tabla que registra un momento en lugar de un intervalo, y hace que cada bloque dure defaultDurationMinutes; no cero, porque en un bloque sin altura no se puede hacer clic. |
title | string | no | El campo del que se lee la primera línea del bloque. Si falta, es el campo principal de la tabla, que es lo que ya muestran una cuadrícula, un panel de búsqueda y una ruta de navegación. |
category | string | no | Un campo de elección, estado o motivo cuyas opciones colorean los bloques y rellenan la leyenda. |
bookedFor | string | no | El campo que indica para quién es la franja, que se muestra de forma discreta bajo el título. De cualquier tipo: una búsqueda se resuelve en el nombre del registro de destino. |
note | string | no | El campo que se muestra en un bloque lo bastante alto para una tercera línea y, si no, en su información sobre herramientas. |
defaultScale | string | no | En qué hoja se abre la vista: Day, Week (predeterminado) o Month. |
startHour | integer | no | La primera hora que muestran las hojas de día y de semana, 0–23. 0 de forma predeterminada. |
endHour | integer | no | La hora en la que terminan esas hojas, 1–24, y mayor que startHour. 24 de forma predeterminada. |
defaultDurationMinutes | integer | no | Cuánto dura una franja cuando el lector hace clic en una vacía —la duración con la que llega el nuevo registro— y la altura de cada bloque en una vista que no asigna end. Al menos 1; 60 de forma predeterminada. |
🔴 start y end deben ser campos de fecha y hora, y category debe tener colores. Ambas
cosas se rechazan al guardar, porque ambas fallan en silencio en pantalla: un start que es una
columna de texto dibuja una hoja vacía, que se lee como «no hay nada reservado esta semana»,
justo la conclusión sobre la que un lector actuará y que no puede comprobar. El color reside en las
propias opciones de la elección, y eso es lo que permite decir una sola vez «Examen es ámbar» y que
lo lean por igual el calendario, una celda de cuadrícula y un gráfico.
startHour y endHour marcan la diferencia entre una hoja de reservas útil y una que se abre con
dos tercios vacíos: una clínica que trabaja de 8 a 19 no quiere dieciséis filas de medianoche.
Indican dónde se abre la hoja: el lector sigue pudiendo cambiar de escala y acotar las horas
desde el propio encabezado de la hoja, porque la ventana es suya y no del creador.
No hay, a propósito, ningún rol resource. Las hojas muestran los días a lo ancho, así que un
campo que nombrara la columna a la que pertenece un bloque sería una asignación que un creador
podría hacer y luego ver que no hace nada. Llegará con el eje que la dibuje.
hierarchy (una vista que se representa como árbol)
Una vista con un bloque hierarchy dibuja sus registros anidados mediante una búsqueda —un
organigrama con las personas de cada unidad, un árbol de categorías, una lista de materiales— en
lugar de como una cuadrícula. Si falta, es la cuadrícula que siempre ha sido cada vista, y por eso
todas las vistas almacenadas siguen siendo válidas.
Un árbol sirve para navegar: las filas se obtienen por ventanas, de modo que un organigrama de cincuenta mil personas se abre sin cargar ninguna de ellas.
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
nodeTypes | array | sí | Todos los tipos de nodo que puede dibujar el árbol. Al menos uno. |
order | array | no | El orden en que se dibujan los segmentos bajo un nodo, por id de tipo de nodo. Si falta, es el orden de declaración. |
rootPicker | boolean | no | Indica si un lector puede centrar el árbol en un nodo: abrirlo en una ciudad en lugar de en toda la organización. |
expandRoots | boolean | no | Indica si el primer nivel se abre al cargar. true de forma predeterminada. |
Cada entrada de nodeTypes:
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
id | string | sí | Cómo se llama este tipo dentro del bloque: unit, person. Único aquí, y aquello a lo que hacen referencia order y cada childOf.of. La misma tabla puede aparecer dos veces en un organigrama, y por eso es una palabra del propio creador y no un nombre de tabla. |
entity | string | sí | La tabla de la que son registros estos nodos. |
childOf | object | sí | Cómo cuelga este tipo de su padre; vea más abajo. |
label | string | no | El campo cuyo valor es la línea del nodo. Si falta, es el campo principal de la tabla. |
secondary | string | no | El campo que se muestra de forma discreta tras la etiqueta. Si falta, es el propio campo secundario de la tabla; una cadena vacía significa ninguno: en una unidad, el nombre del padre es la fila justo encima, así que un organigrama es un sitio en el que la segunda línea predeterminada de una tabla no sirve. |
icon | string | no | El glifo de la fila. Si falta, es el propio icono de la tabla. |
image | boolean | no | Indica si la fila lleva la imagen del registro. |
detail | object | no | Lo que llena el panel junto al organigrama cuando se selecciona uno. Si falta, es el formulario principal de la tabla. |
childOf recibe un field —la búsqueda de la tabla de este tipo que contiene el registro
padre— y un of opcional, el tipo de nodo del que cuelga, por id.
🔴 Exactamente un tipo de nodo omite of. Ese es la propia tabla del árbol anidada bajo sí
misma, y sus registros con el padre vacío son el nivel superior del organigrama; todos los demás
tipos nombran aquello de lo que cuelgan. Los nodos heterogéneos son el caso general y no un
añadido: unidades y luego las personas que hay en ellas es el mismo mecanismo que provincia →
ciudad → sucursal modelado como tres tablas.
La búsqueda que nombra childOf.field debe apuntar a la tabla del tipo padre (a la suya propia,
en el tipo raíz). Una que apunte a cualquier otro sitio no describe un anidamiento, y se
rechaza al guardar en lugar de mostrar un nivel sin nada debajo.
detail recibe un kind de Form (el propio formulario de la tabla, guardado mediante la ruta de
escritura del formulario de registro), Card (una vista de tarjeta pensada para leerse y no para
escribir en ella, que suele ser lo que se quiere para una persona bajo una unidad) o None (para
un tipo que solo es estructura), más un name opcional que indica qué formulario o vista de
tarjeta.
columnProperties (cómo se presenta una columna)
Una lista dispersa: solo aparecen las columnas que ha configurado un creador, y una columna sin
entrada se representa solo a partir de los metadatos de su campo. Se sitúa junto a columns en
lugar de convertirla en una lista de objetos, de modo que todas las definiciones v1 siguen siendo
válidas y no se toca ningún lector que solo necesite saber qué columnas tiene una vista.
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
field | string | sí | La columna que configura. Debe ser una de las columns de la vista. |
label | string | null | no | Sustitución del encabezado. Si falta, se usa el nombre para mostrar del campo. |
width | integer | null | no | Ancho en píxeles, 40–1200. Si falta, la columna ajusta su propio tamaño. |
format | string | null | no | Formato del valor. Para una columna DateTime, el mismo conjunto de tokens que aceptan los controles de fecha del formulario (yyyy, yy, MM, dd, HH, mm, ss): un único vocabulario de formato en todo el producto. |
align | string | null | no | start, center o end. Lógico, no izquierda/derecha, de modo que sigue la dirección de lectura (§6.13.6). |
controlType | string | null | no | El control con el que se representa la columna: un glifo de interruptor para un booleano, una fecha persa para una fecha. |
controlType admite Text, TextArea, Check, Toggle, Date, DateTime, Time,
PersianDate, PersianDateTime, PersianTime, Lookup, PolymorphicLookup, Dropdown o
Label. Si falta, hereda el valor predeterminado del propio campo y, después, el del tipo de
datos.
🔴 Siempre se representa como de solo lectura. Una cuadrícula no tiene edición en línea, así
que un interruptor aquí muestra el estado en lugar de aceptar un clic. También es la única
forma de que una columna muestre el calendario jalalí en un inquilino gregoriano, ya que format
es un patrón sin calendario asociado.
commandOverrides (cambiar un comando propiedad de la plataforma)
Lo que esta vista cambia de los comandos integrados: Nuevo, Editar, Eliminar, Actualizar, Guardar, Guardar y cerrar, Anclar. Si falta, no cambia nada, que es lo que significa toda vista creada antes de que esto existiera.
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
command | string | sí | El id estable del comando que se sustituye. |
label | string | no | Sustituye la etiqueta de la plataforma. Si falta, se conserva, incluidas sus traducciones, que una sustitución escrita pierde necesariamente. |
icon | string | no | Sustituye el glifo de la plataforma. |
initiallyHidden | boolean | no | Indica si el comando empieza oculto. |
initiallyDisabled | boolean | no | Indica si el comando empieza deshabilitado. |
🔴 Se identifica por un id de comando estable, nunca por etiqueta ni posición. El id es el nombre propio de la plataforma y no cambia cuando cambia la etiqueta, así que una sustitución no puede desvincularse de lo que sustituye en cuanto alguien la edita; y un comando integrado puede renombrarse o retirarse más adelante sin que haya que conciliar cada documento almacenado, ya que una sustitución que nombra un comando que ya no existe simplemente se ignora.
🔴 Un creador puede ocultar y deshabilitar, nunca mostrar ni habilitar. El reproductor oculta Nuevo a quien no puede crear y deshabilita Eliminar cuando no hay nada seleccionado; una sustitución capaz de deshacer eso construiría una barra que ofrece lo que el servidor rechazará.
«Inicialmente» es todo el significado de la palabra. Es el estado en el que se abre la barra, no una condición permanente: una regla de negocio o el propio script del comando pueden mostrarlo después. Un comando que nunca debe aparecer para alguien no es esto; eso es un permiso, que se decide en el servidor, donde un navegador no puede rebatirlo.
commandOrder (una barra, un orden)
Los comandos integrados y los del propio creador, intercalados tal como los dispuso el creador, por id.
Una lista explícita en lugar de un rango en cada comando, porque un rango hay que reescribirlo en todos los comandos cada vez que uno se mueve, y dos comandos pueden tener el mismo: un empate que el renderizador resolvería de forma distinta a como lo resolvió el diseñador.
🔴 Todo lo que esta lista no menciona conserva su lugar natural, al final. Eso es lo que hace que la regla resista el paso del tiempo: un comando integrado que se añada a la plataforma el año que viene, o un comando que añada una actualización, aparece en lugar de desaparecer porque un orden almacenado es anterior a él. Un id que nombra algo que ya no existe se omite.
rowSelection (si las filas llevan una casilla)
true de forma predeterminada, y lo que significa toda vista creada antes de que esto existiera:
la cuadrícula tiene su encabezado de seleccionar todo y una casilla por fila, que es sobre lo que
actúa la barra de comandos.
false es para una vista que solo se lee —una lista desde la que nadie elimina ni reasigna—,
donde una casilla ofrece una selección múltiple que la superficie no necesita y cuesta una columna
de ancho.
filterGroup (AND/OR jerárquico)
Un filterGroup es un nodo recursivo que combina sus miembros con un connector:
| Campo | Tipo | Obligatorio | Notas |
|---|---|---|---|
connector | string | sí | And (coinciden todos los miembros) u Or (coincide cualquier miembro). |
conditions | array | no | Condiciones hoja (field, operator, value) de este grupo. |
groups | array | no | Subgrupos anidados (con la misma forma), para un anidamiento AND/OR arbitrario. |
Ejemplo
{
"logicalName": "par_invoice_active",
"displayName": "Active Invoices",
"entity": "par_invoice",
"viewType": "Public",
"columns": ["par_name", "par_total"],
"filters": [ { "field": "par_total", "operator": "GreaterThan", "value": 0 } ],
"filterGroup": {
"connector": "And",
"conditions": [ { "field": "par_name", "operator": "Contains", "value": "INV" } ],
"groups": [
{
"connector": "Or",
"conditions": [
{ "field": "par_total", "operator": "GreaterThan", "value": 1000 },
{ "field": "par_total", "operator": "IsNull" }
]
}
]
},
"sorts": [ { "field": "par_name", "descending": false } ]
}
Ejemplo: una vista de búsqueda
{
"logicalName": "par_contact_pick",
"displayName": "Contact Lookup",
"entity": "par_contact",
"viewType": "Lookup",
"columns": ["par_name", "par_email", "par_city"],
"sorts": [ { "field": "par_name", "descending": false } ]
}
Ejemplo: una vista de búsqueda rápida
Solo se lee columns: son las columnas con las que se compara una búsqueda escrita.
{
"logicalName": "par_contact_find",
"displayName": "Contact Quick Find",
"entity": "par_contact",
"viewType": "QuickFind",
"columns": ["par_name", "par_email", "par_accountnumber"]
}