mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 21:54:56 +00:00
Merge pull request #158 from johndoe6345789/codex/update-legacy-action-types-in-json-configs
Migrate JSON pages to json-ui action/conditional syntax and improve event/expression handling
This commit is contained in:
@@ -27,6 +27,7 @@ Use the `expression` field to evaluate dynamic values:
|
||||
- Supports nested objects using dot notation
|
||||
|
||||
- **Event Access**: `"event.target.value"`, `"event.key"`, `"event.type"`
|
||||
- You can also reference the full event payload with `"event"`
|
||||
- Access event properties
|
||||
- Commonly used for form inputs
|
||||
|
||||
@@ -110,6 +111,20 @@ To update nested values inside a data source, use a dotted `target` where the pr
|
||||
|
||||
This dotted `target` format works with `set-value`, `update`, `toggle-value`, `increment`, and `decrement`.
|
||||
|
||||
## Conditional Expressions
|
||||
|
||||
Conditional rendering uses `conditional.if` strings that are evaluated against the current data context:
|
||||
|
||||
```json
|
||||
{
|
||||
"conditional": {
|
||||
"if": "statusFilter === 'running'"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Legacy conditional objects (with `source`/`operator`/`value`) should be migrated to these inline expressions so schemas stay compatible with the JSON UI renderer.
|
||||
|
||||
### create
|
||||
Add a new item to an array data source.
|
||||
|
||||
|
||||
@@ -106,7 +106,12 @@ Converted three complex pages (Models, Component Trees, and Workflows) from trad
|
||||
"type": "Component",
|
||||
"bindings": { "prop": { "source": "...", "path": "..." } },
|
||||
"events": [
|
||||
{ "event": "click", "actions": [...] }
|
||||
{
|
||||
"event": "click",
|
||||
"actions": [
|
||||
{ "type": "set-value", "target": "selectedId", "expression": "event" }
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
@@ -115,6 +120,18 @@ Converted three complex pages (Models, Component Trees, and Workflows) from trad
|
||||
}
|
||||
```
|
||||
|
||||
### Action & Conditional Syntax
|
||||
- Use supported JSON UI action types (for example, `set-value`, `toggle-value`, `show-toast`) with `target`, `path`, `value`, or `expression` fields instead of legacy `setState` actions.
|
||||
- Replace legacy conditional objects (`{ "source": "...", "operator": "eq|gt|truthy|falsy", "value": ... }`) with `conditional.if` expressions:
|
||||
|
||||
```json
|
||||
{
|
||||
"conditional": {
|
||||
"if": "modelCount === 0"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Component Registry Integration
|
||||
All JSON page wrappers are registered in `component-registry.ts`:
|
||||
- `JSONModelDesigner`
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "createBlueprintDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -150,9 +150,7 @@
|
||||
"className": "p-4 space-y-2"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "blueprintCount",
|
||||
"operator": "gt",
|
||||
"value": 0
|
||||
"if": "blueprintCount > 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -165,11 +163,7 @@
|
||||
"className": "group cursor-pointer hover:bg-accent/10 transition-all duration-200 hover:shadow-lg hover:shadow-accent/20 border-2 hover:border-accent/50"
|
||||
},
|
||||
"conditionalClass": {
|
||||
"condition": {
|
||||
"source": "selectedBlueprintId",
|
||||
"operator": "eq",
|
||||
"valueFrom": "item.id"
|
||||
},
|
||||
"condition": "selectedBlueprintId === item.id",
|
||||
"trueClass": "bg-accent/20 border-accent shadow-md shadow-accent/30",
|
||||
"falseClass": "border-transparent"
|
||||
},
|
||||
@@ -178,9 +172,9 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "selectedBlueprintId",
|
||||
"valueFrom": "item.id"
|
||||
"expression": "event.item.id"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -330,9 +324,7 @@
|
||||
"className": "flex flex-col items-center justify-center h-full p-8 text-center"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "blueprintCount",
|
||||
"operator": "eq",
|
||||
"value": 0
|
||||
"if": "blueprintCount === 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -367,7 +359,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "createBlueprintDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -404,8 +396,7 @@
|
||||
"className": "flex-1 overflow-auto p-8"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "selectedBlueprint",
|
||||
"operator": "truthy"
|
||||
"if": "selectedBlueprint"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -467,7 +458,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "toast",
|
||||
"type": "show-toast",
|
||||
"message": "Edit blueprint coming soon",
|
||||
"variant": "info"
|
||||
}
|
||||
@@ -496,7 +487,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "createEndpointDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -662,9 +653,7 @@
|
||||
"className": "space-y-3"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "endpointCount",
|
||||
"operator": "gt",
|
||||
"value": 0
|
||||
"if": "endpointCount > 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -743,7 +732,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "toast",
|
||||
"type": "show-toast",
|
||||
"message": "Edit endpoint coming soon",
|
||||
"variant": "info"
|
||||
}
|
||||
@@ -804,9 +793,7 @@
|
||||
"className": "text-center py-12"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "endpointCount",
|
||||
"operator": "eq",
|
||||
"value": 0
|
||||
"if": "endpointCount === 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -835,7 +822,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "createEndpointDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -869,8 +856,7 @@
|
||||
"className": "flex-1 flex items-center justify-center p-8"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "selectedBlueprint",
|
||||
"operator": "falsy"
|
||||
"if": "!selectedBlueprint"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
|
||||
@@ -96,7 +96,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "createDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -128,9 +128,7 @@
|
||||
"className": "space-y-2"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "lambdaCount",
|
||||
"operator": "gt",
|
||||
"value": 0
|
||||
"if": "lambdaCount > 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -145,9 +143,7 @@
|
||||
"className": "flex flex-col items-center justify-center py-12 px-4 text-center"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "lambdaCount",
|
||||
"operator": "eq",
|
||||
"value": 0
|
||||
"if": "lambdaCount === 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -191,8 +187,7 @@
|
||||
"className": "flex-1 flex items-center justify-center p-8"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "selectedLambda",
|
||||
"operator": "truthy"
|
||||
"if": "selectedLambda"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -248,8 +243,7 @@
|
||||
"className": "flex-1 flex items-center justify-center p-8"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "selectedLambda",
|
||||
"operator": "falsy"
|
||||
"if": "!selectedLambda"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
|
||||
@@ -20,9 +20,7 @@
|
||||
"className": "text-xs"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "badge",
|
||||
"operator": "neq",
|
||||
"value": null
|
||||
"if": "badge !== null"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -33,9 +33,7 @@
|
||||
"className": "flex items-center gap-1.5 text-xs text-muted-foreground"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "lastSaved",
|
||||
"operator": "neq",
|
||||
"value": null
|
||||
"if": "lastSaved !== null"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
|
||||
@@ -31,9 +31,9 @@
|
||||
"event": "onChange",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "searchValue",
|
||||
"valueFrom": "event.target.value"
|
||||
"expression": "event.target.value"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -48,16 +48,14 @@
|
||||
"className": "absolute right-1 h-7 w-7 p-0"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "searchValue",
|
||||
"operator": "neq",
|
||||
"value": ""
|
||||
"if": "searchValue !== \"\""
|
||||
},
|
||||
"events": [
|
||||
{
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "searchValue",
|
||||
"value": ""
|
||||
}
|
||||
|
||||
@@ -314,9 +314,9 @@
|
||||
"event": "onValueChange",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "selectedTab",
|
||||
"valueFrom": "event"
|
||||
"expression": "event"
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -571,7 +571,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "customColorDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -602,9 +602,7 @@
|
||||
"className": "text-center py-8"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "customColorCount",
|
||||
"operator": "eq",
|
||||
"value": 0
|
||||
"if": "customColorCount === 0"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -630,9 +628,7 @@
|
||||
"className": "text-sm text-muted-foreground"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "customColorCount",
|
||||
"operator": "gt",
|
||||
"value": 0
|
||||
"if": "customColorCount > 0"
|
||||
},
|
||||
"children": "Custom colors will be displayed here"
|
||||
}
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
"event": "onClick",
|
||||
"actions": [
|
||||
{
|
||||
"type": "setState",
|
||||
"type": "set-value",
|
||||
"target": "createDialogOpen",
|
||||
"value": true
|
||||
}
|
||||
@@ -131,9 +131,7 @@
|
||||
{
|
||||
"type": "div",
|
||||
"conditional": {
|
||||
"source": "workflowCount",
|
||||
"operator": "eq",
|
||||
"value": 0
|
||||
"if": "workflowCount === 0"
|
||||
},
|
||||
"props": {
|
||||
"className": "text-center py-8 text-muted-foreground"
|
||||
@@ -158,8 +156,7 @@
|
||||
"className": "flex-1 flex items-center justify-center"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "selectedWorkflow",
|
||||
"operator": "falsy"
|
||||
"if": "!selectedWorkflow"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
@@ -204,8 +201,7 @@
|
||||
"className": "flex-1 p-6 overflow-auto"
|
||||
},
|
||||
"conditional": {
|
||||
"source": "selectedWorkflow",
|
||||
"operator": "truthy"
|
||||
"if": "selectedWorkflow"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
|
||||
@@ -102,7 +102,10 @@ export function ComponentRenderer({ component, data, context = {}, state, onEven
|
||||
? handler.condition(mergedData as Record<string, any>)
|
||||
: evaluateCondition(handler.condition, mergedData as Record<string, any>))
|
||||
if (conditionMet) {
|
||||
onEvent(component.id, handler, e)
|
||||
const eventPayload = typeof e === 'object' && e !== null
|
||||
? Object.assign(e as Record<string, unknown>, context)
|
||||
: e
|
||||
onEvent(component.id, handler, eventPayload)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -26,6 +26,14 @@ export function evaluateExpression(
|
||||
const { data, event } = context
|
||||
|
||||
try {
|
||||
if (expression === 'event') {
|
||||
return event
|
||||
}
|
||||
|
||||
if (expression === 'data') {
|
||||
return data
|
||||
}
|
||||
|
||||
// Handle direct data access: "data.fieldName"
|
||||
if (expression.startsWith('data.')) {
|
||||
return getNestedValue(data, expression.substring(5))
|
||||
|
||||
@@ -157,7 +157,10 @@ export function JSONUIRenderer({
|
||||
: evaluateCondition(handler.condition, { ...dataMap, ...renderContext })
|
||||
if (!conditionMet) return
|
||||
}
|
||||
onAction?.(handler.actions, event)
|
||||
const eventPayload = typeof event === 'object' && event !== null
|
||||
? Object.assign(event, renderContext)
|
||||
: event
|
||||
onAction?.(handler.actions, eventPayload)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user