diff --git a/lowcode/schema/definitions/form-descriptor.schema.json b/lowcode/schema/definitions/form-descriptor.schema.json new file mode 100644 index 0000000000..60a0b14f0e --- /dev/null +++ b/lowcode/schema/definitions/form-descriptor.schema.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "form-descriptor.schema.json", + "title": "FormDescriptor", + "description": "Describes a named form definition bound to an entity", + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "Unique identifier for the form", + "minLength": 1 + }, + "entityName": { + "type": "string", + "description": "Full name of the entity this form is bound to (e.g., 'Namespace.EntityName')", + "minLength": 1 + }, + "fields": { + "type": "array", + "description": "Flat list of all field definitions in this form", + "items": { + "$ref": "form-field-descriptor.schema.json" + } + }, + "layout": { + "$ref": "form-layout-descriptor.schema.json" + }, + "rules": { + "type": "array", + "description": "Conditional rules for field/group visibility and enabled state", + "items": { + "$ref": "form-rule-descriptor.schema.json" + } + } + }, + "required": ["name", "entityName", "fields", "layout"], + "additionalProperties": false +} diff --git a/lowcode/schema/definitions/form-field-descriptor.schema.json b/lowcode/schema/definitions/form-field-descriptor.schema.json new file mode 100644 index 0000000000..b5334cc583 --- /dev/null +++ b/lowcode/schema/definitions/form-field-descriptor.schema.json @@ -0,0 +1,61 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "form-field-descriptor.schema.json", + "title": "FormFieldDescriptor", + "description": "Describes a single field in a form", + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for this field within the form", + "minLength": 1 + }, + "label": { + "type": "string", + "description": "Display label for the field", + "minLength": 1 + }, + "type": { + "$ref": "form-field-type.schema.json" + }, + "binding": { + "type": ["string", "null"], + "description": "Entity property name to bind to, or null for unbound fields. Supports dotted paths like 'Parent.Name' for related entity display." + }, + "enumType": { + "type": "string", + "description": "Full enum type name for select fields" + }, + "defaultValue": { + "description": "Default value for the field" + }, + "placeholder": { + "type": "string", + "description": "Placeholder text for the input" + }, + "helpText": { + "type": "string", + "description": "Help text displayed below the field" + }, + "readOnly": { + "type": "boolean", + "description": "Whether the field is read-only", + "default": false + }, + "modeVisibility": { + "type": "string", + "enum": ["both", "createOnly", "editOnly"], + "description": "Controls in which form mode the field is visible", + "default": "both" + }, + "validations": { + "type": "array", + "description": "Form-level validation rules (override or extend entity-level validators)", + "items": { + "$ref": "validator-descriptor.schema.json" + } + } + }, + "required": ["id", "label", "type"], + "additionalProperties": false +} diff --git a/lowcode/schema/definitions/form-field-type.schema.json b/lowcode/schema/definitions/form-field-type.schema.json new file mode 100644 index 0000000000..03af7d0117 --- /dev/null +++ b/lowcode/schema/definitions/form-field-type.schema.json @@ -0,0 +1,18 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "form-field-type.schema.json", + "title": "FormFieldType", + "description": "Available field types for form fields", + "type": "string", + "enum": [ + "text", + "textarea", + "number", + "checkbox", + "date", + "select", + "lookup", + "guid", + "computed" + ] +} diff --git a/lowcode/schema/definitions/form-layout-descriptor.schema.json b/lowcode/schema/definitions/form-layout-descriptor.schema.json new file mode 100644 index 0000000000..74457b0ed6 --- /dev/null +++ b/lowcode/schema/definitions/form-layout-descriptor.schema.json @@ -0,0 +1,105 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "form-layout-descriptor.schema.json", + "title": "FormLayoutDescriptor", + "description": "Describes the visual layout of a form (tabs > groups > field placements)", + "type": "object", + "properties": { + "tabs": { + "type": "array", + "description": "Ordered list of tabs in the form", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for this tab", + "minLength": 1 + }, + "title": { + "type": "string", + "description": "Display title for the tab", + "minLength": 1 + }, + "isDefault": { + "type": "boolean", + "description": "Whether this is the default tab (cannot be deleted, receives orphaned fields)", + "default": false + }, + "groups": { + "type": "array", + "description": "Ordered list of groups within this tab", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for this group", + "minLength": 1 + }, + "title": { + "type": ["string", "null"], + "description": "Optional display title for the group" + }, + "isDefault": { + "type": "boolean", + "description": "Whether this is the default group (cannot be deleted, receives orphaned fields)", + "default": false + }, + "rows": { + "type": "array", + "description": "Ordered list of layout rows; each row contains one or more cells (fields placed side-by-side)", + "items": { + "type": "object", + "properties": { + "cells": { + "type": "array", + "description": "Fields placed side-by-side in this row (total colSpan should not exceed 4)", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "fieldId": { + "type": "string", + "description": "Reference to a field id in the form's fields array", + "minLength": 1 + }, + "colSpan": { + "type": "integer", + "description": "Number of grid columns this field spans (1-4)", + "minimum": 1, + "maximum": 4, + "default": 4 + }, + "colStart": { + "type": "integer", + "description": "Starting grid column (1-4). Omit or null to auto-place after the previous cell.", + "minimum": 1, + "maximum": 4 + } + }, + "required": ["fieldId"], + "additionalProperties": false + } + } + }, + "required": ["cells"], + "additionalProperties": false + } + } + }, + "required": ["id", "rows"], + "additionalProperties": false + } + } + }, + "required": ["id", "title", "groups"], + "additionalProperties": false + } + } + }, + "required": ["tabs"], + "additionalProperties": false +} diff --git a/lowcode/schema/definitions/form-rule-descriptor.schema.json b/lowcode/schema/definitions/form-rule-descriptor.schema.json new file mode 100644 index 0000000000..aeee227991 --- /dev/null +++ b/lowcode/schema/definitions/form-rule-descriptor.schema.json @@ -0,0 +1,71 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "form-rule-descriptor.schema.json", + "title": "FormRuleDescriptor", + "description": "Describes a conditional rule with one or more actions that execute when the condition is met", + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "Unique identifier for this rule", + "minLength": 1 + }, + "name": { + "type": "string", + "description": "Human-readable name for this rule (optional)" + }, + "condition": { + "type": "object", + "description": "The condition that triggers this rule", + "properties": { + "fieldId": { + "type": "string", + "description": "The field whose value is evaluated", + "minLength": 1 + }, + "operator": { + "type": "string", + "enum": ["equals", "notEquals", "isEmpty", "isNotEmpty"], + "description": "Comparison operator" + }, + "value": { + "description": "The value to compare against (not used for isEmpty/isNotEmpty)" + } + }, + "required": ["fieldId", "operator"], + "additionalProperties": false + }, + "actions": { + "type": "array", + "description": "Actions to perform when condition is met (executed in order)", + "minItems": 1, + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "enum": ["hide", "show", "disable", "enable", "setValue"], + "description": "The action type" + }, + "targetType": { + "type": "string", + "enum": ["field", "group"], + "description": "Whether the target is a field or a group" + }, + "targetId": { + "type": "string", + "description": "The id of the target field or group", + "minLength": 1 + }, + "value": { + "description": "The value to set (only for setValue action)" + } + }, + "required": ["type", "targetType", "targetId"], + "additionalProperties": false + } + } + }, + "required": ["id", "condition", "actions"], + "additionalProperties": false +} diff --git a/lowcode/schema/definitions/page-descriptor.schema.json b/lowcode/schema/definitions/page-descriptor.schema.json index 952fafdb47..b328dbe073 100644 --- a/lowcode/schema/definitions/page-descriptor.schema.json +++ b/lowcode/schema/definitions/page-descriptor.schema.json @@ -36,14 +36,51 @@ "type": "integer", "description": "Menu sort order (lower values appear first)", "default": 0 + }, + "formName": { + "type": "string", + "description": "Name of the form to render (required when type is 'form')", + "minLength": 1 + }, + "createFormName": { + "type": "string", + "description": "Name of the form to use for creating entities (for dataGrid/kanban pages)" + }, + "editFormName": { + "type": "string", + "description": "Name of the form to use for editing entities (for dataGrid/kanban pages)" + }, + "createFormDisplay": { + "type": "string", + "enum": ["modal", "page"], + "description": "How to display the create form", + "default": "modal" + }, + "editFormDisplay": { + "type": "string", + "enum": ["modal", "page"], + "description": "How to display the edit form", + "default": "modal" } }, "required": ["name", "title", "type", "entityName"], - "if": { - "properties": { "type": { "const": "kanban" } } - }, - "then": { - "required": ["groupByProperty"] - }, + "allOf": [ + { + "if": { + "properties": { "type": { "const": "kanban" } } + }, + "then": { + "required": ["groupByProperty"] + } + }, + { + "if": { + "properties": { "type": { "const": "form" } } + }, + "then": { + "required": ["formName"] + } + } + ], "additionalProperties": false } diff --git a/lowcode/schema/definitions/page-type.schema.json b/lowcode/schema/definitions/page-type.schema.json index f26132b189..8a185619fe 100644 --- a/lowcode/schema/definitions/page-type.schema.json +++ b/lowcode/schema/definitions/page-type.schema.json @@ -4,5 +4,5 @@ "title": "PageType", "description": "The type of page to render", "type": "string", - "enum": ["dataGrid", "kanban", "calendar"] + "enum": ["dataGrid", "kanban", "calendar", "form"] } diff --git a/lowcode/schema/model.schema.json b/lowcode/schema/model.schema.json index c328002d37..2315475939 100644 --- a/lowcode/schema/model.schema.json +++ b/lowcode/schema/model.schema.json @@ -36,6 +36,13 @@ "items": { "$ref": "definitions/page-descriptor.schema.json" } + }, + "forms": { + "type": "array", + "description": "List of named form definitions for entity create/edit", + "items": { + "$ref": "definitions/form-descriptor.schema.json" + } } }, "additionalProperties": false