Browse Source

Document Low-Code 10.7 feature workflows

Document Low-Code 10.7 feature workflows
rel-10.7
Enis Necipoglu 14 hours ago
committed by GitHub
parent
commit
6ede07be5a
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 12
      docs/en/docs-nav.json
  2. 11
      docs/en/low-code/custom-endpoints.md
  3. 116
      docs/en/low-code/data-import.md
  4. 248
      docs/en/low-code/data-modeling.md
  5. 24
      docs/en/low-code/designer.md
  6. 7
      docs/en/low-code/foreign-access.md
  7. 7
      docs/en/low-code/health.md
  8. 13
      docs/en/low-code/index.md
  9. 2
      docs/en/low-code/mcp.md
  10. 111
      docs/en/low-code/model-history.md
  11. 19
      docs/en/low-code/model-json.md
  12. 13
      docs/en/low-code/react-runtime.md

12
docs/en/docs-nav.json

@ -2153,6 +2153,18 @@
"text": "Low-Code Designer",
"path": "low-code/designer.md"
},
{
"text": "Data Modeling and Page Behavior",
"path": "low-code/data-modeling.md"
},
{
"text": "Data Import",
"path": "low-code/data-import.md"
},
{
"text": "Model History and Recovery",
"path": "low-code/model-history.md"
},
{
"text": "Calculated and Rollup Properties",
"path": "low-code/formula-properties.md"

11
docs/en/low-code/custom-endpoints.md

@ -41,9 +41,16 @@ Custom endpoints are defined in JSON descriptor files or through the Low-Code De
| `javascript` | string | Required | JavaScript handler code |
| `description` | string | null | Optional designer/documentation text |
| `requireAuthentication` | bool | `true` | Whether the caller must be authenticated |
| `useResourceAuthorization` | bool | `false` | Whether execution is granted per endpoint name through ABP resource permissions |
| `requiredPermissions` | string[] | null | Permission names required to call the endpoint |
Permission checks require an authorized user even when `requireAuthentication` is set to `false`. Keep endpoints authenticated by default and use `requireAuthentication: false` only for intentionally public APIs without `requiredPermissions`.
Authorization is resolved in this order:
1. When `requiredPermissions` contains values, every named permission is required.
2. Otherwise, `useResourceAuthorization: true` requires the endpoint execute resource permission scoped to the endpoint name, with the global Low-Code endpoint permission as fallback.
3. Otherwise, `requireAuthentication` selects authenticated or public access.
Permission checks require an authorized user even when `requireAuthentication` is set to `false`. Keep endpoints authenticated by default and use `requireAuthentication: false` only for intentionally public APIs without named or resource authorization.
## Route and Request Data
@ -223,7 +230,7 @@ Default blocked headers also include hop-by-hop headers such as `Connection`, `T
## Security Notes
* Prefer authenticated endpoints with explicit `requiredPermissions`.
* Treat endpoints with `requireAuthentication: false` and no `requiredPermissions` as public API surface.
* Treat endpoints with `requireAuthentication: false`, no `requiredPermissions`, and `useResourceAuthorization: false` as public API surface.
* Keep endpoint scripts small and focused.
* Validate route, query, and body input before using it.
* Use `take()` for list queries.

116
docs/en/low-code/data-import.md

@ -0,0 +1,116 @@
```json
//[doc-seo]
{
"Description": "Import Excel or CSV data into ABP Low-Code pages with guided mapping, append or merge behavior, foreign-key matching, remote files, and invalid-row downloads."
}
```
# Data Import
The React Low-Code runtime can import Excel and CSV files into a dynamic page. The import wizard previews the file in the browser, maps source columns to entity properties, reviews the operation, and sends the file plus the confirmed mapping to the backend.
Import is enabled by default for pages and can be disabled per page with `importEnabled: false`.
## Import Workflow
1. Open a dynamic data page and select **Import**.
2. Upload an Excel or CSV file, or download a sample file for the page.
3. Review the detected columns and map each source column to one target property.
4. Choose **Append** or **Merge**.
5. Review required fields, conversions, relation matching, and file/image sources.
6. Run the import and download the invalid-row file if any rows fail.
Column names are matched automatically when a source header equals a property name or display label after normalizing spaces, underscores, hyphens, dots, and letter casing. Review every automatic mapping before import.
The wizard reports mappings as compatible, convertible, warning, or incompatible. The backend remains authoritative and validates each converted value, entity rule, and mapped property.
## Append and Merge
**Append** creates a new record for every valid row. The `Id` column is not accepted in append mode.
**Merge** uses one mapped property as the match key:
* A matching record is updated.
* A non-matching row creates a record.
* The match property must be included in the column mapping.
* When the selected property can match multiple records, choose either **Error** or **Use first**. **Use first** also requires a deterministic sort property and direction.
Use an ID or unique business key whenever possible. A non-unique merge key makes the result depend on the selected multiple-match rule.
## Foreign-Key Mapping
A foreign-key column can contain the related record ID or another allowed match property such as a unique username or code. The wizard exposes the supported related-entity match fields for that property.
If a foreign-key lookup can return multiple records, the same rules apply:
* **Error** rejects the row.
* **Use first** requires an explicit sort property and direction.
This decision is per mapped foreign-key column, independent of the main append or merge mode.
## Value Extraction
Use a source-value regular expression when a cell contains extra text around the value that should be imported. The expression must contain a named `value` capture group:
```text
Order: (?<value>[A-Z]+-\d+)
```
The server compiles and executes the expression with bounded input, evaluation count, and elapsed-time budgets. A structurally valid client preview does not replace server validation.
## File and Image URLs
File and image properties can import remote files referenced by spreadsheet text. Source modes are:
| Mode | Use it when |
|------|-------------|
| `auto` | The runtime should detect a supported URL shape |
| `fullUrl` | The whole cell is the URL |
| `fileNameAndUrl` | The cell contains a file name and URL |
| `extractUrlFromText` | The URL is embedded in surrounding text |
| `customRegex` | A custom expression extracts a named `url` group |
Remote downloads are performed by the backend, not by the browser. The verified defaults require HTTPS on port `443`, allow only public network destinations, follow at most three redirects, and reject private, link-local, multicast, and loopback destinations. Development loopback HTTP is available only when both the environment is Development and `AllowLoopbackHttpInDevelopment` is enabled.
Restrict production destinations with `LowCode:Import:RemoteFiles:AllowedHosts` when imports should fetch only from known hosts. Download count, per-file bytes, aggregate bytes, concurrency, redirects, and timeout are all bounded by `LowCode:Import:RemoteFiles` options.
Remote files are staged before row persistence. A failed row or failed merge does not replace an existing stored file with an incomplete download.
## Partial Failures
Import continues after row-scoped validation or conversion failures. The result reports:
* Total rows
* Succeeded and failed rows
* Created and updated records
* A short-lived invalid-row download token when failures exist
The invalid-row file contains the original row values plus failure details so the rows can be corrected and imported again. The verified default token lifetime is 600 seconds.
Failures that make the whole request unsafe, such as an invalid archive, exceeded global file budget, or blocked remote destination, stop the import before normal row processing.
## Limits and Configuration
Important verified defaults are:
| Setting | Default |
|---------|---------|
| `LowCode:Import:MaxRows` | `10000` |
| `LowCode:Import:MaxColumns` | `256` |
| `LowCode:Import:InvalidRowsTokenLifetimeSeconds` | `600` |
| `LowCode:Import:RemoteFiles:Enabled` | `true` |
| `LowCode:Import:RemoteFiles:RequestTimeoutSeconds` | `15` |
| `LowCode:Import:RemoteFiles:MaxConcurrentDownloads` | `4` |
| `LowCode:Import:RemoteFiles:MaxFilesPerImport` | `500` |
| `LowCode:Import:RemoteFiles:MaxFileBytes` | `10485760` |
| `LowCode:Import:RemoteFiles:MaxTotalBytesPerImport` | `104857600` |
| `LowCode:Import:RemoteFiles:AllowedPorts` | `[443]` |
The options validators reject non-positive, inconsistent, or above-ceiling values. Keep imports page-scoped and use the existing limits instead of accepting arbitrary workbook sizes.
## See Also
* [React Runtime](react-runtime.md)
* [Data Modeling and Page Behavior](data-modeling.md)
* [Model Descriptor Files](model-json.md)
* [Foreign Access](foreign-access.md)

248
docs/en/low-code/data-modeling.md

@ -0,0 +1,248 @@
```json
//[doc-seo]
{
"Description": "Model Low-Code property storage, primitive collections, related fields, presentations, backend filters, and page or relationship permissions."
}
```
# Data Modeling and Page Behavior
The Low-Code Designer can model more than scalar fields and basic CRUD pages. This page covers the data and page features that affect storage, queries, presentation, and authorization.
## Property Storage
Scalar properties use one of two storage shapes:
* `isMappedToDbField: true` maps the property to its own physical column.
* An omitted or `false` `isMappedToDbField` stores the property through the entity's dynamic data mapping.
By default, dynamic data mapping uses the entity's JSON `Data` column. Applications that need individual columns for those properties can disable JSON data storage while configuring EF Core:
```csharp
builder.ConfigureDynamicEntities(useJsonDataStorage: false);
```
The equivalent module option is `AbpLowCodeEntityFrameworkCoreOptions.UseJsonDataStorage`. Its verified default is `true`.
Changing the storage mode or `isMappedToDbField` affects the physical schema. Decide the storage strategy before creating production tables, then use the normal migration or runtime schema workflow for later changes. Formulas and rollups are virtual and do not create physical scalar columns.
Source-model and runtime-model dynamic tables can use separate prefixes:
```csharp
LowCodeDbProperties.JsonModelTablePrefix = "Src_";
LowCodeDbProperties.RuntimeTablePrefix = "Runtime_";
```
Configure prefixes before the dynamic model is initialized. Changing a prefix after tables exist requires renaming or migrating those tables.
## Primitive Collections
A primitive collection keeps an ordered list of values on one property. Supported element types are `string`, `int`, `long`, `decimal`, `dateTime`, `boolean`, `guid`, `enum`, `date`, `time`, `money`, `file`, and `image`.
```json
{
"name": "Tags",
"type": "string",
"collection": {
"maxCount": 25,
"uniqueItems": true,
"storageKey": "b7db3ad2-3452-511b-b9b7-cc11d2db6dcb"
}
}
```
Collection rules:
* `maxCount` is optional, but must be greater than zero when supplied.
* `uniqueItems` is required and controls duplicate-value validation.
* The effective item limit is the lower of `maxCount` and `LowCode:PrimitiveCollections:MaximumItemsPerProperty`. The verified global default is `1000`.
* `storageKey` is a stable internal identity used by the normalized collection table. Let the Designer generate it and do not change it after data exists.
* A collection property cannot also be a foreign key, formula, or rollup.
Collections are stored in normalized rows rather than inside the owner JSON payload. The React runtime returns them as ordered arrays and uses collection-aware controls for scalar, enum, file, and image values.
## Related Fields and Self-Relations
Page columns and filters can follow foreign keys by using dot-separated property paths:
```json
{
"columns": [
{ "propertyName": "CustomerId.Name", "label": "Customer" },
{ "propertyName": "CustomerId.CountryId.Name", "label": "Country" }
],
"filters": [
{ "propertyName": "CustomerId.CountryId.RegionId.Name" }
]
}
```
Only requested related fields are projected into the response. The same paths can be used by page filtering and export, including registered reference entities.
Self-relations are supported. For example, an employee page can use `ManagerId.ManagerId.Name` to follow the same relation more than once. Every path is still limited by the configured maximum foreign-key depth exposed by the Low-Code query capabilities.
## Reverse Relationships
A foreign key defines the schema direction. A page relationship defines how records that point back to the host record are shown and edited:
```json
{
"name": "Authors",
"entityName": "Acme.Authors.Author",
"relationships": [
{
"id": "author-books",
"sourceEntityName": "Acme.Books.Book",
"sourcePropertyName": "AuthorId",
"access": "edit",
"relatedPageMode": "page",
"relatedPageName": "Books",
"createFormMode": "generated",
"editFormMode": "form",
"editFormName": "BookEditForAuthor"
}
]
}
```
`access` can be `none`, `view`, or `edit`. The generated modes build the related page or form from the source entity; the explicit modes reuse named page and form descriptors.
See [Foreign Access](foreign-access.md) for the runtime APIs and UI behavior used by these relationships.
## Enum and Boolean Presentation
Enum values can define reusable display metadata:
```json
{
"name": "Acme.Orders.OrderStatus",
"values": [
{
"name": "Pending",
"value": 10,
"displayName": "Waiting",
"presentation": "badge",
"color": "#F59E0B"
}
]
}
```
Enum presentation supports `text`, `badge`, and `iconOnly`. Pages can override the display name, presentation, color, or icon for one property without changing the shared enum:
```json
{
"enumPresentations": [
{
"propertyName": "Status",
"values": [
{ "value": 10, "displayName": "Awaiting review", "presentation": "badge", "color": "#F59E0B" }
]
}
]
}
```
Boolean columns support `text`, `checkbox`, `badge`, and `iconOnly`, with separate metadata for `true`, `false`, and `null`:
```json
{
"propertyName": "IsActive",
"booleanPresentation": "badge",
"booleanValues": {
"true": { "displayName": "Active", "color": "#16A34A" },
"false": { "displayName": "Inactive", "color": "#DC2626" },
"null": { "displayName": "Not set", "color": "#6B7280" }
}
}
```
Icons can reference a CSS class, stored blob, data URL, or application path. Runtime-layer writes apply stricter icon validation than source-controlled descriptors.
## Backend Filters
Visible page filters are controlled by the user. A backend filter is always applied by the server and is useful for tenant, ownership, role, or workflow scoping.
```json
{
"backendFilter": {
"items": [
{
"propertyName": "Status",
"operator": "equal",
"value": "Active"
},
{
"logic": "or",
"items": [
{
"propertyName": "CreatorId",
"operator": "equal",
"valueProvider": "CurrentUserId"
},
{
"logic": "and",
"propertyName": "AllowedRole",
"operator": "in",
"valueProvider": "CurrentUserRoles"
}
]
}
]
}
}
```
A filter value can be:
* Static through `value`.
* Resolved by JavaScript through `javaScript`.
* Resolved by a registered provider through `valueProvider`.
Built-in providers cover the current user ID, username, first name, surname, email, email verification, phone number, phone verification, roles, and current tenant ID. Applications can register additional typed providers with `AbpLowCodePageBackendFilterOptions`.
Backend filters are combined with search and user-selected filters. They are not sent as editable client state, so do not replace them with a hidden React filter when the rule is security-sensitive.
## Page and Relationship Permissions
Pages use resource-based authorization by default. `permissionConfig` can keep that generated default, require a named permission, allow any authenticated user, or make an operation public:
```json
{
"permissionConfig": {
"view": "default",
"create": "Acme.Orders.Create",
"update": "authenticated",
"delete": "Acme.Orders.Delete"
}
}
```
For generated reverse relationships, enable separate authorization when child access must not inherit the host page decision:
```json
{
"id": "author-books",
"sourceEntityName": "Acme.Books.Book",
"sourcePropertyName": "AuthorId",
"access": "edit",
"useSeparatePermission": true,
"permissionConfig": {
"view": "default",
"create": "Acme.Books.Create",
"update": "Acme.Books.Update",
"delete": "Acme.Books.Delete"
}
}
```
When `useSeparatePermission` is `true`, generated relationship permissions are scoped to the host page and relationship ID. Create, update, and delete also require relationship view access.
## See Also
* [Low-Code Designer](designer.md)
* [Model Descriptor Files](model-json.md)
* [Calculated and Rollup Properties](formula-properties.md)
* [Data Import](data-import.md)
* [Foreign Access](foreign-access.md)
* [React Runtime](react-runtime.md)

24
docs/en/low-code/designer.md

@ -40,9 +40,9 @@ The selected layer controls whether the designer can save changes. Read-only lay
Use **Data** to define the domain model.
Entities contain properties, display names, display property configuration, inherited audit fields, relations, and optional interceptors. Enums are created once and then used by enum properties.
Entities contain properties, display names, display property configuration, inherited audit fields, relations, primitive collections, and optional interceptors. Enums are created once and then used by enum properties. Enum and boolean values can also carry text, badge, color, and icon presentation metadata.
For virtual fields derived from the current record or related records, see [Calculated and Rollup Properties](formula-properties.md). For the supported scalar formula syntax, see the [Low-Code Expression Language](expression-language.md) reference.
For storage choices, primitive collections, related-field paths, presentations, and backend filters, see [Data Modeling and Page Behavior](data-modeling.md). For virtual fields derived from the current record or related records, see [Calculated and Rollup Properties](formula-properties.md). For the supported scalar formula syntax, see the [Low-Code Expression Language](expression-language.md) reference.
![Entity summary in the designer](images/designer-entity.png)
@ -50,7 +50,7 @@ For virtual fields derived from the current record or related records, see [Calc
### Relations
Relations are driven by foreign key properties. The designer shows direct N to 1 relations and many-to-many relations that are modeled through junction entities.
Relations are driven by foreign key properties. The designer shows direct N to 1 relations, self-relations, and many-to-many relations that are modeled through junction entities. Page columns, filters, and exports can select related fields through foreign-key paths, and reverse page relationships can use generated or named pages/forms with view or edit access.
![Relation overview](images/designer-relations.png)
@ -73,6 +73,8 @@ Pages can define data grid, kanban, calendar, gallery, standalone form, and dash
* Field labels and column widths
* Default sorting
* Filter fields and defaults
* Always-on backend filters with static, JavaScript, or registered-provider values
* Guided Excel and CSV import, including append or merge behavior
* File/image export defaults when the page has exportable file fields
* Whether file bundle ZIP export is allowed
@ -86,6 +88,8 @@ The **View Fields** section controls what users see in the runtime view. The sep
Open **Export Fields > More settings** only when you need custom export details. If **Use default export settings** is enabled, export uses display labels, the view field order, file name output, and file bundle export enabled. Turn it off to customize export labels, assign a separate export order, choose **Default File/Image Output**, or disable **Allow file bundle export**. File/image output controls appear only when the page has file or image fields, and they stay inactive until at least one file/image field is exportable.
Use [Data Import](data-import.md) for the runtime import wizard, column mapping, merge keys, foreign-key matching, remote file/image sources, and invalid-row downloads.
## Forms
Use **Forms** to define create and edit experiences.
@ -147,12 +151,16 @@ Filters are configured per page and rendered by the React runtime. The runtime u
The URL query parameter keeps the existing `lcFilters` format, so bookmarked filtered pages continue to work.
Backend filters are different from the visible filters above: the server always combines them with the user's query. Use them for ownership, tenant, role, and workflow scopes that must not be removable from the client. See [Data Modeling and Page Behavior](data-modeling.md#backend-filters).
## Permissions
Dynamic permissions are generated for entities and pages. Use the **Permissions** section to review names and grant access through the normal ABP permission management UI.
Dynamic permissions are generated for entities, pages, custom endpoints, and optionally individual page relationships. Use the **Permissions** section to review names and grant access through the normal ABP permission management UI.
Generated pages and menus are permission-aware. If a user cannot access a page, the runtime does not show the menu item and API calls remain protected by backend authorization.
Pages use resource permissions by default and can override each operation with `default`, `public`, `authenticated`, or a named permission. Generated reverse relationships can enable separate view/create/update/delete authorization. See [Data Modeling and Page Behavior](data-modeling.md#page-and-relationship-permissions).
## Actions and Scripts
Use **Actions** only when descriptor metadata and standard CRUD behavior are not enough. The scripting surface can define custom HTTP endpoints, distributed event handlers, background jobs, and scheduled background workers. Scripts run server-side and use the [Scripting API](scripting-api.md).
@ -165,9 +173,15 @@ Endpoint and event handler editors include **Test JavaScript**. Dry-run executio
Use **Health** before shipping changes. It helps catch missing display properties, invalid relation targets, form/page references, script problems, and other model issues that would otherwise surface at runtime. See [Health](health.md) for the selected-layer snapshot scope and the typical problem classes it helps you review.
## History and Recovery
When **Runtime JSON** is selected, the Designer exposes runtime model undo, redo, history details, comparisons, and save points. History actions are previewed against a concurrency stamp and require explicit confirmation before destructive physical schema changes.
Entity deletion also uses a reviewed plan. You must resolve dependent relationships and choose whether Designer-managed physical data is kept or deleted. An entity deleted with retained physical data can be restored only from a fresh schema and concurrency preview. See [Model History and Recovery](model-history.md).
## MCP Integration
The Designer and the low-code MCP surface overlap when the selected layer is **Runtime JSON**, but they are not the same editing surface. The Designer can inspect source-controlled and runtime layers, while [MCP Integration](mcp.md) is a remote HTTP MCP endpoint that is intentionally runtime-only and targets the database-backed model. Use the Designer when you want interactive editing and visual feedback. Use MCP when an authenticated agent or script needs repeatable runtime automation.
The Designer and the low-code MCP surface overlap when the selected layer is **Runtime JSON**, but they are not the same editing surface. The Designer can inspect source-controlled and runtime layers, while [MCP Integration](mcp.md) is a remote HTTP MCP endpoint that is intentionally runtime-only and targets the database-backed model. MCP exposes the same model-management semantics documented in the general Low-Code feature pages; it is not a separate feature model. Use the Designer when you want interactive editing and visual feedback. Use MCP when an authenticated agent or script needs repeatable runtime automation.
After MCP-driven changes, reopen the relevant Designer section or review [Health](health.md) before reporting the model as ready.

7
docs/en/low-code/foreign-access.md

@ -13,6 +13,8 @@ Use the [Low-Code Designer](designer.md) to review relation metadata visually. T
Foreign Access controls how related **dynamic entities** can be accessed through foreign key relationships. It determines whether users can view or manage related data directly from the **target entity's** UI.
The foreign key defines the schema relation and default reverse-access level. A page can additionally define a page-specific relationship that selects generated or named related pages/forms and separate authorization. See [Data Modeling and Page Behavior](data-modeling.md#reverse-relationships).
> **Important:** Foreign Access only works between **dynamic entities**. It does not apply to [reference entities](reference-entities.md) because they are read-only and don't have UI pages.
## Access Levels
@ -126,10 +128,14 @@ An **action menu item** appears on the target entity's data grid row (e.g., an "
No action menu item is added. The foreign key exists only for data integrity and lookup display.
Self-relations are supported. For example, an `Employee.ManagerId` foreign key can expose direct reports on the employee page, while page columns and filters can follow paths such as `ManagerId.ManagerId.Name` within the configured query-depth limit.
## Permission Control
Foreign access actions respect the **entity permissions** of the source entity (the entity with the foreign key). For example, if a user does not have the `Delete` permission for `Order`, the delete button will not appear in the foreign access modal, even if the access level is `Edit`.
A generated page relationship can set `useSeparatePermission: true`. In that mode, view/create/update/delete access is resolved for the host page and relationship ID instead of relying only on the source entity permission. Relationship create, update, and delete also require relationship view access.
## How It Works
The `ForeignAccessRelation` class stores the relationship metadata:
@ -146,5 +152,6 @@ The `DynamicEntityAppService` checks these relations when building entity action
## See Also
* [Model Descriptor Files](model-json.md)
* [Data Modeling and Page Behavior](data-modeling.md)
* [Reference Entities](reference-entities.md)
* [Attributes & Fluent API](fluent-api.md)

7
docs/en/low-code/health.md

@ -41,20 +41,26 @@ Typical problem classes include:
* Form layout issues where fields exist but valid placements do not
* Permission and page configuration mismatches that would affect runtime visibility or access
* Script assets that exist in the model but still need review in the broader context of entities, pages, and permissions
* Orphaned upper-layer descriptors whose lower-layer base was removed or disabled
Some of these issues are also enforced by runtime validation and mutation rules. Health gives you a selected-layer review point before users discover the problem in the runtime UI.
When orphan warnings are present, preview the matching inactive-override or disabled-override cleanup before applying it. Cleanup removes only the affected authored deltas from the selected writable layer; review the preview because enabled sibling deltas on the same descriptor are preserved.
## Use It When
Use Health in these moments:
* After changing entities, pages, forms, page groups, or permissions in the Designer
* After applying MCP-driven runtime mutations
* After undo, redo, save-point restore, retained-entity restore, or override cleanup
* Before publishing a set of runtime changes
* After copying or importing source-controlled descriptors into an application
If you automate low-code changes through [MCP Integration](mcp.md), re-read the health snapshot after apply and treat that review as part of the success criteria.
For runtime history, safe entity deletion, and retained-data restoration, see [Model History and Recovery](model-history.md).
## Health and Source-Controlled Models
Health is not a replacement for source-controlled file validation.
@ -78,6 +84,7 @@ A useful example is form layout drift: a descriptor can still pass `--check-lowc
* [Low-Code Designer](designer.md)
* [MCP Integration](mcp.md)
* [Model History and Recovery](model-history.md)
* [Model Descriptor Files](model-json.md)
* [Dashboards](dashboards.md)
* [Page Groups](page-groups.md)

13
docs/en/low-code/index.md

@ -22,6 +22,7 @@ Use the designer to model entities, enums, properties, relations, pages, forms,
* React data grid, kanban, calendar, gallery, form, and dashboard pages
* Create and edit forms
* Advanced filters
* Guided Excel and CSV import with append or merge behavior
* Excel, CSV, and file bundle export
No DTO, repository, application service, controller, or React CRUD page is required for the standard flow.
@ -98,13 +99,15 @@ The generated startup project accepts `--model-directory <path-to-_Dynamic/model
The designer is the day-to-day entry point.
1. Use **Data** to create entities, enums, properties, and relations.
2. Use **Pages** to choose a page type, menu placement, fields, default sorting, filters, dashboards, and linked forms.
1. Use **Data** to create entities, enums, properties, primitive collections, and relations.
2. Use **Pages** to choose a page type, menu placement, related fields, default sorting, visible and backend filters, import, dashboards, and linked forms.
3. Use **Forms** to arrange create and edit forms with tabs, groups, controls, validations, and actions.
4. Use **Permissions** to review generated permissions and control access.
5. Use **Actions** and **Interceptors** when the standard CRUD flow needs custom logic, endpoints, event handlers, jobs, or workers.
6. Use **Health** to review model issues before publishing changes.
Runtime JSON changes also have model history, undo/redo, comparisons, and save points. Entity deletion uses a reviewed impact plan and can retain Designer-managed physical data for later restoration. See [Model History and Recovery](model-history.md).
The screens below follow that common designer flow from data to page setup to forms:
![Entity properties in the designer](images/designer-properties.png)
@ -176,6 +179,9 @@ The designer stores and reads the same descriptor metadata described in the refe
| Topic | Use it for |
|-------|------------|
| [Designer](designer.md) | Admin Console tabs, entity/page/form setup, permissions, and health |
| [Data Modeling and Page Behavior](data-modeling.md) | Property storage, primitive collections, related fields, presentations, backend filters, and relationship permissions |
| [Data Import](data-import.md) | Excel/CSV mapping, append and merge, foreign-key matching, remote files, and invalid rows |
| [Model History and Recovery](model-history.md) | Runtime undo/redo, save points, comparison, safe deletion, and retained-data restore |
| [Calculated and Rollup Properties](formula-properties.md) | Virtual scalar formulas and related-record aggregates authored in the Designer |
| [Low-Code Expression Language](expression-language.md) | Provider-safe scalar syntax used by calculated properties and formula backfills |
| [Add Low-Code to an Existing Solution](add-to-existing-solution.md) | Retrofitting an existing EF Core solution with Studio import plus manual backend and React wiring |
@ -209,6 +215,9 @@ The generated pages are powered by these services:
## See Also
* [Low-Code Designer](designer.md)
* [Data Modeling and Page Behavior](data-modeling.md)
* [Data Import](data-import.md)
* [Model History and Recovery](model-history.md)
* [Calculated and Rollup Properties](formula-properties.md)
* [Low-Code Expression Language](expression-language.md)
* [Add Low-Code to an Existing Solution](add-to-existing-solution.md)

2
docs/en/low-code/mcp.md

@ -13,6 +13,8 @@ The Low-Code Designer exposes a **remote Model Context Protocol (MCP) server** f
Use [Model Descriptor Files](model-json.md) when you need source-controlled `_Dynamic/model/**/*.json` files. Use MCP when an agent or automation needs authenticated, structured runtime access that the Designer can immediately show.
MCP uses the same Low-Code feature model as the Designer. Use [Data Modeling and Page Behavior](data-modeling.md), [Data Import](data-import.md), [Calculated and Rollup Properties](formula-properties.md), and [Model History and Recovery](model-history.md) for feature semantics; this page only covers MCP connection and safe automation concerns.
## Remote Endpoint
The low-code MCP endpoint is hosted by the backend application that includes the Low-Code Designer HTTP API module:

111
docs/en/low-code/model-history.md

@ -0,0 +1,111 @@
```json
//[doc-seo]
{
"Description": "Use ABP Low-Code runtime model history, undo and redo, save points, comparison, safe entity deletion, and retained-data restoration."
}
```
# Model History and Recovery
The Low-Code Designer records applied mutation batches for history-enabled writable layers. In the standard setup, the history controls operate on the **Runtime JSON** layer. Source-controlled descriptor changes continue to use Git and the normal migration workflow.
The Designer toolbar exposes **Undo history**, **Redo history**, and **History** when the selected layer supports these operations.
## History Batches
Each successful model write is recorded as a batch with:
* Sequence and creation information
* Forward and inverse operations
* Before and after concurrency stamps
* Checkpoints within the operation list
* Status, source kind, and schema-impact metadata
History is model history, not record audit history. It tracks changes to entities, pages, forms, permissions, scripts, and other descriptors; it does not list CRUD changes made to business records.
The history list is paged independently from the save-point list. The verified defaults keep up to 200 history batches and 100 save points per runtime layer. Retention can be changed through `LowCodeRuntimeHistoryOptions`.
## Undo, Redo, and Targeted Actions
Available history actions are:
| Action | Purpose |
|--------|---------|
| Undo | Apply the inverse of the current applied batch |
| Redo | Reapply the next undone batch |
| Go to checkpoint | Move the history cursor to a before/after checkpoint |
| Revert range | Revert a selected range of batches |
| Go to save point | Move through retained history to the save point cursor |
| Restore save point | Restore the full model snapshot saved at that point |
| Apply operation | Apply one selected operation from a history batch |
Use **Go to save point** when its history cursor is still available. Use **Restore save point** when the exact cursor is no longer retained or when the saved snapshot is the intended source of truth.
## Preview Before Apply
Every history action can be previewed before it writes. The preview reports:
* Whether the action is valid
* Current concurrency stamp and conflicts
* Ordered operations
* Schema impact
* Whether destructive schema confirmation is required
* Warnings and structured conflicts
Apply the action with the same current concurrency stamp used by the reviewed preview. If the model changes between preview and apply, refresh history and preview again.
History actions do not drop physical tables or columns by default. When a preview reports destructive schema impact, the apply request requires explicit destructive confirmation. Review the affected operations and data-loss impact before enabling it.
## Save Points and Compare
A save point stores a named model snapshot plus its history cursor. Create one before a coordinated set of runtime changes or before a risky schema edit.
History comparison can compare current, save-point, before-save, after-save, and operation-checkpoint states. The result contains forward and inverse operations and reports both general and destructive schema impact without changing the model.
Comparison and history actions are protected by entry, operation, and serialized-payload budgets. Old history can be pruned while a save point retains its snapshot for later comparison or restore.
## Safe Entity Deletion
Entity deletion is a planned operation. Before the Designer deletes an entity, it builds a plan containing:
* Descriptors that will be removed with it
* Relationships that need resolution
* Blocking references
* Affected physical tables
* Whether each table is Designer-managed or migration-managed
* Current concurrency stamp and a plan fingerprint
For each resolvable relationship, choose one of the actions offered by the plan, such as removing the source property or converting it to a scalar. The apply step rejects stale plans and unreviewed relationship decisions.
Designer-managed tables require an explicit data choice:
* **Keep physical data** removes the model descriptors while retaining the physical table and its file, image, attachment, and collection data.
* **Delete physical data** drops eligible physical tables and deletes their associated stored data.
Migration-managed entities cannot be physically dropped by the runtime Designer. Their plan requires the migration path to be acknowledged instead.
## Restore Retained Entity Data
When an entity was deleted with **Keep physical data**, the Designer can preview and restore its retained table. The preview reports the table, row count, property shape, retained physical object ID, schema fingerprint, and current concurrency stamp.
Restore only from a fresh preview. The apply request must repeat its exact:
* `retainedPhysicalObjectId`
* `schemaFingerprint`
* `concurrencyStamp`
The server rejects a stale concurrency stamp, changed schema, mismatched retained object, or already-restored table. A successful restore recreates the entity descriptor against the retained physical data instead of copying the rows into a new table.
Keeping physical data is not a backup strategy. Retention metadata remains part of the same application database and should be covered by the application's normal backup and recovery process.
## MCP Automation
The runtime-only [MCP Integration](mcp.md) exposes the same history, comparison, formula/rollup, safe-deletion, and retained-restore service workflows. MCP clients should follow the feature semantics on this page, preview destructive operations, preserve concurrency stamps, and re-read [Health](health.md) after apply.
## See Also
* [Low-Code Designer](designer.md)
* [Health](health.md)
* [MCP Integration](mcp.md)
* [Model Descriptor Files](model-json.md)
* [Calculated and Rollup Properties](formula-properties.md)

19
docs/en/low-code/model-json.md

@ -237,10 +237,15 @@ Entities describe the persisted data model. UI is not configured with legacy pro
| `isUnique` | Unique value validation |
| `serverOnly` | Hidden from clients, API responses, and UI metadata |
| `allowSetByClients` | Whether create/update clients may set this value |
| `isMappedToDbField` | Whether the property is stored in the database |
| `isMappedToDbField` | Whether a dynamic scalar property uses a dedicated physical column instead of dynamic data storage |
| `decimalPlaces` | Decimal scale for `decimal` and `money` properties |
| `currencySymbol` | Optional UI currency symbol for `money` properties |
| `collection` | Primitive collection settings: `maxCount`, required `uniqueItems`, and stable `storageKey` |
| `foreignKey` | Lookup relation metadata |
| `validators` | Backend/UI validation rules |
`isMappedToDbField: true` creates a dedicated scalar column. Other dynamic scalar properties use the configured dynamic data mapping, which is JSON storage by default and can be configured as individual columns. Primitive collections use normalized collection tables. See [Data Modeling and Page Behavior](data-modeling.md) for storage, collections, related fields, presentations, and backend filters.
For virtual calculated fields and related-record aggregates, see [Calculated and Rollup Properties](formula-properties.md). The [Low-Code Expression Language](expression-language.md) reference documents the scalar syntax used by calculated properties and formula backfills.
### Property Types
@ -256,6 +261,8 @@ For virtual calculated fields and related-record aggregates, see [Calculated and
| `enum` | Integer-backed enum; requires `enumType` |
| `file`, `image` | Upload metadata handled by the low-code file pipeline |
Add `collection` to any supported primitive type to store an ordered value list. Do not hand-edit a generated `storageKey` after data exists.
### File, Image, and Attachments
Use `file` or `image` properties for first-class upload fields:
@ -339,6 +346,7 @@ Pages create runtime routes and menu entries. They also choose how entity data i
"type": "dataGrid",
"entityName": "Acme.Catalog.Product",
"group": "catalog",
"importEnabled": true,
"defaultFileExportMode": 0,
"allowFileBundleExport": true,
"columns": [
@ -372,6 +380,10 @@ Page export settings:
| `defaultFileExportMode` | `0` | Default spreadsheet output for file/image fields. `0` = file name, `1` = metadata columns, `2` = temporary download-link columns |
| `allowFileBundleExport` | `true` | Allows **Files (.zip)** export for exportable file/image columns on the page |
`importEnabled` controls whether the React runtime exposes guided Excel/CSV import for the page. See [Data Import](data-import.md) for mapping and merge behavior.
Page column and filter `propertyName` values may follow foreign keys, for example `CustomerId.CountryId.Name`. Related paths are limited by the configured query depth and return only the requested projection. Page columns can also define enum and boolean presentation metadata. See [Data Modeling and Page Behavior](data-modeling.md).
ZIP file bundle export only includes selected page columns that are file or image fields and are exportable. The ZIP contains `manifest.csv` plus files under `files/{recordId}/{fieldName}/{safeFileName}`.
| Page type | Required fields | Purpose |
@ -451,6 +463,8 @@ Filters are page-owned. Use `control: "auto"` unless you need a specific control
`hasValue` is a UI alias. At runtime, `Yes` maps to `IsNotNull`, `No` maps to `IsNull`, and `All` does not add a filter.
Use a page `backendFilter` when a condition must always be applied by the server. The recursive expression supports `and`/`or` groups and static, JavaScript, or registered-provider values. Backend filters are combined with the filters above and are not removable client state. See [Data Modeling and Page Behavior](data-modeling.md#backend-filters).
## Permissions
Pages can use generated defaults or explicit permission configuration:
@ -468,6 +482,8 @@ Pages can use generated defaults or explicit permission configuration:
Custom permission definitions live in the top-level `permissions` section and can be granted through the normal ABP permission management UI.
`default` uses the generated page resource permission; `authenticated` allows any authenticated caller; `public` allows anonymous access; any other value is treated as a named permission. Reverse page relationships can set `useSeparatePermission: true` and provide their own view/create/update/delete configuration. See [Data Modeling and Page Behavior](data-modeling.md#page-and-relationship-permissions).
## Scripts
### Interceptors
@ -496,6 +512,7 @@ See [Interceptors](interceptors.md) and [Scripting API](scripting-api.md).
"route": "/api/custom/products/stats",
"method": "GET",
"requireAuthentication": true,
"useResourceAuthorization": false,
"requiredPermissions": ["Acme.Catalog"],
"javascript": "var count = await db.count('Acme.Catalog.Product'); return ok({ total: count });"
}

13
docs/en/low-code/react-runtime.md

@ -133,6 +133,8 @@ The generated data grid page includes:
Create and edit forms are rendered from form metadata. Tabs, groups, labels, placeholders, controls, default values, validation rules, conditional form rules, and save actions come from the designer.
Primitive collection properties render collection-aware controls and are sent as ordered arrays. Scalar and enum collections support add/remove/reorder behavior; file and image collections use the same upload validation as single-value file fields. Per-property and global collection limits are enforced by the backend. See [Data Modeling and Page Behavior](data-modeling.md#primitive-collections).
Rendered groups come from the form layout placements under `layout.tabs[].groups[].fields[]`. A form can still load with an empty shell when fields exist but no placements reference them.
![Generated create form](images/runtime-create-form.png)
@ -157,6 +159,14 @@ The screenshot below shows the shared selector pattern on the `Active` boolean f
The URL keeps the existing `lcFilters` query parameter shape. The runtime maps user-friendly filter choices to the existing backend `FilterType` values.
Columns and filters can request related fields through foreign-key paths such as `CustomerId.CountryId.Name`, including repeated self-relations within the configured query-depth limit. Enum and boolean columns render their configured text, badge, color, and icon presentation. Server-owned backend filters are applied in addition to the visible filters and cannot be removed by changing `lcFilters`.
## Data Import
Pages with import enabled expose a guided Excel/CSV import wizard. It previews the file, maps source columns to writable properties, supports append and merge modes, resolves foreign keys through allowed match properties, and reports row-scoped failures in a downloadable invalid-row file.
File and image mappings can fetch approved remote HTTPS URLs through the backend's bounded network guard. See [Data Import](data-import.md) for the complete workflow, security defaults, and configuration limits.
## Export
The runtime export button opens a small menu with direct Excel and CSV actions. If the selected page has exportable file or image fields and bundle export is allowed in the Designer, the menu also shows **Files (.zip)**. Direct export uses the current search, sorting, filters, and visible exportable columns from the page definition maintained in the Low-Code Designer. Use **Export options** when users need a different row, column, or file output scope.
@ -267,6 +277,9 @@ The React runtime talks to these backend endpoints:
| `PUT /api/low-code/pages/{pageName}/data/{id}` | Update record |
| `DELETE /api/low-code/pages/{pageName}/data/{id}` | Delete record |
| `GET /api/low-code/pages/{pageName}/lookup/{fieldName}` | Lookup options |
| `GET /api/low-code/pages/{pageName}/import/sample-file` | Download an Excel or CSV import template |
| `POST /api/low-code/pages/{pageName}/import` | Import a mapped Excel or CSV file |
| `GET /api/low-code/pages/{pageName}/import/invalid-rows` | Download row-scoped import failures by token |
| `POST /api/low-code/pages/{pageName}/files/{fieldName}` | Upload file/image field |
| `GET /api/low-code/pages/{pageName}/data/{id}/files/{fieldName}/{blobName}` | Download file/image field |
| `GET /api/low-code/pages/{pageName}/data/{id}/attachments` | List attachments |

Loading…
Cancel
Save