@ -0,0 +1,183 @@ |
|||||
|
```json |
||||
|
//[doc-seo] |
||||
|
{ |
||||
|
"Description": "Define ABP Low-Code dashboard pages, visualizations, filters, layout, permissions, and React runtime data flow." |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
# Dashboards |
||||
|
|
||||
|
Dashboards are low-code pages that render charts, lists, and number widgets from low-code entity data. A dashboard is still a page, so it uses the normal page name, title, icon, order, group, and permission model, but its page type is `dashboard` and its page definition carries a nested `dashboard` payload. |
||||
|
|
||||
|
The runtime below was generated from a low-code dashboard page definition: |
||||
|
|
||||
|
 |
||||
|
|
||||
|
## Dashboard Pages |
||||
|
|
||||
|
Dashboard pages live in the normal page descriptor collection. In source-controlled models, a dashboard page still belongs under `pages/`, not a separate dashboard folder. |
||||
|
|
||||
|
Typical page-level fields include: |
||||
|
|
||||
|
* `name` |
||||
|
* `title` |
||||
|
* `icon` |
||||
|
* `type: "dashboard"` |
||||
|
* `group` |
||||
|
* `order` |
||||
|
* `permissionConfig` |
||||
|
* `dashboard` |
||||
|
|
||||
|
Runtime routes use the same dynamic page convention: |
||||
|
|
||||
|
```text |
||||
|
/dynamic/<page-name> |
||||
|
``` |
||||
|
|
||||
|
## Layout Model |
||||
|
|
||||
|
The stored dashboard descriptor uses a **flat visualization list**. Each visualization defines its own placement: |
||||
|
|
||||
|
* `row`: zero-based visual row index |
||||
|
* `order`: order within the row |
||||
|
* `width`: current dashboard grid width, typically `1` or `2` |
||||
|
|
||||
|
At runtime, the React UI groups those flat visualizations into rendered rows. This is similar to form layouts: storage stays flat, rendering derives the grouped structure. |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"name": "sales-dashboard", |
||||
|
"title": "Sales Dashboard", |
||||
|
"type": "dashboard", |
||||
|
"group": "analytics", |
||||
|
"dashboard": { |
||||
|
"description": "Operational sales view", |
||||
|
"globalFilters": [ |
||||
|
{ "type": "dateRange" } |
||||
|
], |
||||
|
"visualizations": [ |
||||
|
{ |
||||
|
"name": "sales-by-status", |
||||
|
"type": "chart", |
||||
|
"title": "Sales by Status", |
||||
|
"row": 0, |
||||
|
"order": 0, |
||||
|
"width": 2, |
||||
|
"entityName": "Acme.Sales.Order", |
||||
|
"chart": { |
||||
|
"chartType": "bar", |
||||
|
"xAxis": { "property": "Status" }, |
||||
|
"yAxis": [ |
||||
|
{ "aggregation": "count", "label": "Orders" } |
||||
|
] |
||||
|
} |
||||
|
}, |
||||
|
{ |
||||
|
"name": "totals", |
||||
|
"type": "numberContainer", |
||||
|
"title": "Totals", |
||||
|
"row": 1, |
||||
|
"order": 0, |
||||
|
"width": 2, |
||||
|
"numberContainer": { |
||||
|
"items": [ |
||||
|
{ |
||||
|
"name": "order-count", |
||||
|
"title": "Order Count", |
||||
|
"entityName": "Acme.Sales.Order", |
||||
|
"aggregation": "count", |
||||
|
"format": "number" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
## Visualization Types |
||||
|
|
||||
|
The current dashboard visualization types are: |
||||
|
|
||||
|
* `chart` |
||||
|
* `list` |
||||
|
* `numberContainer` |
||||
|
|
||||
|
### Chart |
||||
|
|
||||
|
Chart visualizations define: |
||||
|
|
||||
|
* `chartType`: `bar`, `line`, `pie`, or `donut` |
||||
|
* `xAxis` |
||||
|
* one or more `yAxis` aggregation series |
||||
|
* optional `maxItems` |
||||
|
* optional `showRecordCount` |
||||
|
* optional bar orientation |
||||
|
|
||||
|
### List |
||||
|
|
||||
|
List visualizations define: |
||||
|
|
||||
|
* `fields` |
||||
|
* optional `sortBy` |
||||
|
* `maxRows` |
||||
|
* `rowHeight` |
||||
|
* optional `colorBy` |
||||
|
|
||||
|
### Number Container |
||||
|
|
||||
|
Number containers hold one or more number items. Each item can define: |
||||
|
|
||||
|
* `aggregation` |
||||
|
* `aggregationProperty` |
||||
|
* `format` |
||||
|
* `color` |
||||
|
* entity-specific filters and global date filter linkage |
||||
|
* click-through behavior |
||||
|
|
||||
|
## Filters and Interactivity |
||||
|
|
||||
|
Dashboards support three filter layers: |
||||
|
|
||||
|
* `globalFilters` for page-level controls such as date range |
||||
|
* visualization-level `filter` for fixed query constraints |
||||
|
* visualization `userFilters` for interactive filtering exposed to the runtime user |
||||
|
|
||||
|
Other useful dashboard interaction fields include: |
||||
|
|
||||
|
* `globalDateFilterProperty` |
||||
|
* `showDescriptionAsTooltip` |
||||
|
* `clickToSeeRecords` |
||||
|
|
||||
|
These options let a dashboard stay compact while still allowing drill-down behavior in the runtime. |
||||
|
|
||||
|
## Runtime Shape |
||||
|
|
||||
|
The runtime definition exposed to React is grouped by rows and items, even though the stored descriptor is flat. The React runtime uses: |
||||
|
|
||||
|
* `useDashboardDefinition` |
||||
|
* `useDashboardData` |
||||
|
* `GET /api/low-code/ui/dashboards/{pageName}` |
||||
|
* `POST /api/low-code/dashboards/{pageName}/data` |
||||
|
|
||||
|
See [React Runtime](react-runtime.md) for hook-level details and route integration. |
||||
|
|
||||
|
## Permissions and Menu Placement |
||||
|
|
||||
|
Dashboard pages are read-oriented. Generated dashboard page operations are **view only**, so the usual CRUD operation set does not apply. |
||||
|
|
||||
|
Dashboard pages can still: |
||||
|
|
||||
|
* appear inside a [Page Group](page-groups.md) |
||||
|
* carry a menu icon and order |
||||
|
* use explicit or generated page permission configuration |
||||
|
|
||||
|
Menu placement is handled at the page level through the normal `group` and `order` fields. |
||||
|
|
||||
|
## See Also |
||||
|
|
||||
|
* [React Runtime](react-runtime.md) |
||||
|
* [Low-Code Designer](designer.md) |
||||
|
* [Page Groups](page-groups.md) |
||||
|
* [Model Descriptor Files](model-json.md) |
||||
@ -0,0 +1,83 @@ |
|||||
|
```json |
||||
|
//[doc-seo] |
||||
|
{ |
||||
|
"Description": "Review the ABP Low-Code model health snapshot to inspect entities, pages, forms, page groups, permissions, and script assets before publishing runtime changes." |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
# Health |
||||
|
|
||||
|
The **Health** section in the Low-Code Designer is a selected-layer readiness view. It helps you review the resolved low-code model for the currently selected layer before publishing changes or relying on the generated runtime pages. |
||||
|
|
||||
|
Health works on the **resolved view of the selected layer**, not on raw JSON files. In practice, this means it shows the selected layer after lower-layer inheritance and descriptor materialization have been applied. It does not silently merge unrelated edits from another layer. To review runtime-only overrides, switch the Designer to **Runtime JSON** or use the runtime-focused [MCP Integration](mcp.md) workflow. |
||||
|
|
||||
|
## What Health Reads |
||||
|
|
||||
|
The health snapshot is a combined view of the current low-code model in the selected layer. It includes: |
||||
|
|
||||
|
* Entities |
||||
|
* Enums |
||||
|
* Page groups |
||||
|
* Pages |
||||
|
* Forms |
||||
|
* Custom permissions |
||||
|
* Effective page permission configuration |
||||
|
* Custom endpoints |
||||
|
* Script event handlers |
||||
|
* Script background jobs |
||||
|
* Script background workers |
||||
|
|
||||
|
This makes Health the best place to review cross-descriptor relationships instead of checking each designer tab in isolation. |
||||
|
|
||||
|
## What It Helps You Catch |
||||
|
|
||||
|
Health is most useful for selected-layer consistency problems that often appear only after several descriptors start referencing each other. |
||||
|
|
||||
|
Typical problem classes include: |
||||
|
|
||||
|
* Page to form mismatches, where a page references a form that does not exist or belongs to another entity |
||||
|
* Page-type configuration errors, such as a kanban page missing `groupByProperty`, a calendar page using invalid date or time fields, or a gallery page pointing to a non-image property |
||||
|
* Page-group structure problems such as missing parents, circular references, or nesting deeper than the supported depth |
||||
|
* 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 |
||||
|
|
||||
|
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. |
||||
|
|
||||
|
## 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 |
||||
|
* 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. |
||||
|
|
||||
|
## Health and Source-Controlled Models |
||||
|
|
||||
|
Health is not a replacement for source-controlled file validation. |
||||
|
|
||||
|
When you edit `_Dynamic/model/**/*.json` directly: |
||||
|
|
||||
|
1. Run the generated model file checker: |
||||
|
|
||||
|
```bash |
||||
|
dotnet run --project <startup-project> -- --check-lowcode-model-files |
||||
|
``` |
||||
|
|
||||
|
2. Run the required migration workflow for schema-affecting entity changes. |
||||
|
3. Open the Designer and review **Health** after the model has loaded successfully. |
||||
|
|
||||
|
The file checker catches JSON and category-level problems. Health complements it by helping you inspect the resolved model after descriptors, references, permissions, pages, and forms are all combined. |
||||
|
|
||||
|
A useful example is form layout drift: a descriptor can still pass `--check-lowcode-model-files` while a source-controlled form renders with no visible fields because its layout placements are stale. Health and runtime preview are the places to catch that class of issue. |
||||
|
|
||||
|
## See Also |
||||
|
|
||||
|
* [Low-Code Designer](designer.md) |
||||
|
* [MCP Integration](mcp.md) |
||||
|
* [Model Descriptor Files](model-json.md) |
||||
|
* [Dashboards](dashboards.md) |
||||
|
* [Page Groups](page-groups.md) |
||||
|
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 55 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 123 KiB |
@ -0,0 +1,126 @@ |
|||||
|
```json |
||||
|
//[doc-seo] |
||||
|
{ |
||||
|
"Description": "Use the ABP Low-Code Designer MCP integration to inspect, validate, and apply structured runtime mutations to the database-backed low-code model." |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
# MCP Integration |
||||
|
|
||||
|
> **Preview:** The low-code MCP surface is part of the preview Low-Code System. Tool names, mutation metadata, and validation advice may change before general availability. |
||||
|
|
||||
|
The low-code designer exposes a Model Context Protocol (MCP) surface for automation. It is intended for agents and scripted tooling that need to inspect or mutate the same **runtime database-backed** model that the Designer edits in the **Runtime JSON** layer. |
||||
|
|
||||
|
## Scope |
||||
|
|
||||
|
The MCP surface is **runtime-only**: |
||||
|
|
||||
|
* It always works against the database-backed runtime model. |
||||
|
* It does not choose between layers at call time. |
||||
|
* It is not the right surface for source-controlled `_Dynamic/model/**/*.json` files. |
||||
|
|
||||
|
Use [Model Descriptor Files](model-json.md) when you need source-controlled descriptors. Use MCP when an agent or automation needs safe, structured changes to the runtime model that the Designer can immediately show. |
||||
|
|
||||
|
## Mental Model |
||||
|
|
||||
|
MCP is not a raw JSON document editor. It is a semantic mutation layer over low-code concepts such as: |
||||
|
|
||||
|
* Entities and properties |
||||
|
* Pages, page groups, and dashboards |
||||
|
* Forms and form layout |
||||
|
* Permissions |
||||
|
* Custom endpoints and script actions |
||||
|
|
||||
|
The MCP surface includes read/query capabilities, mutation metadata, dry-run validation, a single mutation apply path, and a health snapshot. The normal workflow is: |
||||
|
|
||||
|
1. Read the current runtime model state for the item you want to change. |
||||
|
2. Fetch the latest mutation metadata and keep its `concurrencyStamp`. |
||||
|
3. Build a small ordered mutation batch that touches only the changed paths. |
||||
|
4. Dry-run the batch with validation. |
||||
|
5. Apply the batch. |
||||
|
6. Re-read the changed item and review [Health](health.md). |
||||
|
|
||||
|
## Concurrency and Validation |
||||
|
|
||||
|
Every runtime write depends on the latest `concurrencyStamp`. If another write changes the runtime model first, your apply attempt becomes stale and must be rebuilt from the refreshed model state. |
||||
|
|
||||
|
Validation happens before apply and returns structured feedback instead of requiring a client to guess from generic failures. The validation layer checks: |
||||
|
|
||||
|
* Stale concurrency stamps |
||||
|
* Target path syntax |
||||
|
* Missing required input such as `data` or move destinations |
||||
|
* Primitive-only `Set` data |
||||
|
* Final descriptor shape after the batch is simulated |
||||
|
* Entity property type and foreign key rules |
||||
|
* Form layout consistency |
||||
|
* Dashboard layout consistency |
||||
|
* Runtime override rules for descriptors inherited from lower layers |
||||
|
|
||||
|
Treat validation as part of the normal write flow, not as an optional extra. |
||||
|
|
||||
|
## Mutation Model |
||||
|
|
||||
|
Runtime writes are intentionally narrow: |
||||
|
|
||||
|
* `Add` creates a keyed descriptor or collection member. |
||||
|
* `Set` changes a scalar value or a supported primitive list. |
||||
|
* `Remove` deletes the semantic target. |
||||
|
* `Move` relocates an existing node without resending the whole object. |
||||
|
|
||||
|
Important behavior: |
||||
|
|
||||
|
* `Set` data must stay primitive: string, number, boolean, `null`, or a supported primitive string list. |
||||
|
* Do not replace whole descriptor trees when only one field changed. |
||||
|
* Keep batches small and semantic. Send changed paths, not full model payloads. |
||||
|
* If a mapped entity or property is removed with drop behavior, the runtime model can also remove the physical table or column in the runtime layer. |
||||
|
|
||||
|
## Runtime Override and Schema Rules |
||||
|
|
||||
|
Runtime MCP writes can extend descriptors that originate from lower layers, but they do not have unlimited control over inherited schema. |
||||
|
|
||||
|
For entity properties inherited from a lower layer, runtime edits are intentionally restricted. Typical runtime-safe changes are display labels and runtime-owned validators. Inherited storage details such as type, database mapping, default value, required or unique behavior, foreign key settings, and file or image storage options remain immutable in runtime. |
||||
|
|
||||
|
This separation matches the low-code layer model: |
||||
|
|
||||
|
* Runtime database-backed changes use **direct** schema mutation. |
||||
|
* Source-controlled JSON layer changes use the normal **migration** workflow. |
||||
|
|
||||
|
If you are working in `_Dynamic/model`, MCP is the wrong tool. Use the source-controlled descriptor flow and migrations instead. |
||||
|
|
||||
|
## Layout and Type Conventions |
||||
|
|
||||
|
Several conventions matter when MCP clients generate mutations: |
||||
|
|
||||
|
* Use canonical lowercase entity property types: `string`, `int`, `long`, `decimal`, `datetime`, `boolean`, `guid`, `enum`, `date`, `time`, `file`, `image`, `money`. |
||||
|
* Use canonical lowercase form field types: `text`, `textarea`, `number`, `checkbox`, `date`, `datetime`, `select`, `lookup`, `guid`, `computed`, `time`, `file`, `image`, `money`. |
||||
|
* Form layout is flat and id-keyed under `layout.tabs[].groups[].fields[]`. Each placement carries `row`, `colSpan`, and optional `colStart`. |
||||
|
* Dashboard layout is flat and name-keyed under `dashboard.visualizations[]`. Each visualization carries `row`, `order`, and `width`. |
||||
|
* Page and page-group icons are CSS class strings, not URLs or image file paths. |
||||
|
* For foreign access, `foreignKey.access` values are `none`, `view`, or `edit`. |
||||
|
|
||||
|
These rules matter because validation and runtime rendering assume them. For example, a form can define fields correctly but still render an empty group if no valid placements point to those field IDs. |
||||
|
|
||||
|
## Designer and MCP Together |
||||
|
|
||||
|
Use the Designer when you want: |
||||
|
|
||||
|
* Interactive editing |
||||
|
* Visual context for entities, pages, forms, and permissions |
||||
|
* Manual review before publishing |
||||
|
|
||||
|
Use MCP when you want: |
||||
|
|
||||
|
* Agent-driven or scripted changes |
||||
|
* Repeatable runtime mutation workflows |
||||
|
* Structured validation before write |
||||
|
* Safe, incremental edits instead of raw JSON replacement |
||||
|
|
||||
|
The two surfaces are complementary. A common workflow is to inspect or prototype in the Designer, automate a repeatable mutation flow through MCP, then reopen the Designer and [Health](health.md) to confirm the result. |
||||
|
|
||||
|
## See Also |
||||
|
|
||||
|
* [Low-Code Designer](designer.md) |
||||
|
* [Health](health.md) |
||||
|
* [Dashboards](dashboards.md) |
||||
|
* [Page Groups](page-groups.md) |
||||
|
* [Model Descriptor Files](model-json.md) |
||||
@ -0,0 +1,123 @@ |
|||||
|
```json |
||||
|
//[doc-seo] |
||||
|
{ |
||||
|
"Description": "Define ABP Low-Code page groups to organize runtime pages into dynamic menu folders with ordering, icons, and nesting." |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
# Page Groups |
||||
|
|
||||
|
Page groups are dynamic menu folders used by low-code pages. They let you organize runtime pages into nested navigation structures without hardcoding menu items in the frontend. |
||||
|
|
||||
|
## What a Page Group Stores |
||||
|
|
||||
|
A page group descriptor stores: |
||||
|
|
||||
|
| Field | Description | |
||||
|
|-------|-------------| |
||||
|
| `name` | Stable identifier used by pages in their `group` field | |
||||
|
| `title` | Display label shown in the runtime menu | |
||||
|
| `icon` | CSS class string for the menu icon | |
||||
|
| `order` | Sort order among sibling groups | |
||||
|
| `parent` | Optional parent group name for nesting | |
||||
|
|
||||
|
If a group does not define an icon, the runtime menu uses a folder-style default icon. |
||||
|
|
||||
|
## How Pages Use Groups |
||||
|
|
||||
|
Pages reference a group by name: |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"name": "orders", |
||||
|
"title": "Orders", |
||||
|
"type": "dataGrid", |
||||
|
"entityName": "Acme.Sales.Order", |
||||
|
"group": "sales" |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
If `group` is omitted, the page becomes a top-level runtime menu item. |
||||
|
|
||||
|
A group is only a container. It does not define page data, routes, or entity behavior by itself. |
||||
|
|
||||
|
## Nesting Rules |
||||
|
|
||||
|
Groups can nest by pointing `parent` to another page group name. |
||||
|
|
||||
|
Important constraints: |
||||
|
|
||||
|
* Group nesting cannot be circular. |
||||
|
* Maximum depth is `3` levels. |
||||
|
* Root groups are groups whose `parent` is empty. |
||||
|
|
||||
|
This keeps runtime navigation predictable and avoids unbounded nesting in the generated menu. |
||||
|
|
||||
|
## Visibility and Permissions |
||||
|
|
||||
|
Page groups do not replace page permissions. Runtime visibility still depends on the pages inside the group. |
||||
|
|
||||
|
In practice: |
||||
|
|
||||
|
* Pages are added to the runtime menu only if the current user can access them. |
||||
|
* Groups are containers for those visible pages. |
||||
|
* Groups without visible page descendants are omitted from the runtime root menu. |
||||
|
|
||||
|
This means page permissions remain the real security boundary, while page groups control menu organization. |
||||
|
|
||||
|
## Split Descriptor Example |
||||
|
|
||||
|
In split descriptor projects, a page group file in `pageGroups/` stores **one descriptor object**, not a wrapper document: |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"name": "sales-reports", |
||||
|
"title": "Reports", |
||||
|
"icon": "fa-solid fa-folder-tree", |
||||
|
"order": 20, |
||||
|
"parent": "sales" |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
For example, `pageGroups/sales-reports.json` would use that shape directly. |
||||
|
|
||||
|
If you are looking at the logical aggregate model instead of split files, the same data appears under the top-level `pageGroups` array: |
||||
|
|
||||
|
```json |
||||
|
{ |
||||
|
"pageGroups": [ |
||||
|
{ |
||||
|
"name": "sales", |
||||
|
"title": "Sales", |
||||
|
"icon": "fa-solid fa-chart-line", |
||||
|
"order": 10 |
||||
|
}, |
||||
|
{ |
||||
|
"name": "sales-reports", |
||||
|
"title": "Reports", |
||||
|
"icon": "fa-solid fa-folder-tree", |
||||
|
"order": 20, |
||||
|
"parent": "sales" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
|
``` |
||||
|
|
||||
|
In split descriptor projects, page groups belong to the `pageGroups/` descriptor category. |
||||
|
|
||||
|
## Icon Guidance |
||||
|
|
||||
|
Use CSS class strings for icons, for example: |
||||
|
|
||||
|
* `fa-solid fa-folder` |
||||
|
* `fa-solid fa-folder-tree` |
||||
|
* `fa-solid fa-chart-line` |
||||
|
|
||||
|
Do not treat `icon` as an image URL or file path. |
||||
|
|
||||
|
## See Also |
||||
|
|
||||
|
* [Dashboards](dashboards.md) |
||||
|
* [React Runtime](react-runtime.md) |
||||
|
* [Low-Code Designer](designer.md) |
||||
|
* [Model Descriptor Files](model-json.md) |
||||