mirror of
https://github.com/johndoe6345789/low-code-react-app-b.git
synced 2026-04-24 13:44:54 +00:00
Add dialog action handling
This commit is contained in:
@@ -169,7 +169,7 @@ The JSON UI system already supports `events` for action execution and `bindings`
|
||||
"onImport": { "actions": [{ "id": "import-json", "type": "custom" }] },
|
||||
"onExport": { "actions": [{ "id": "export-json", "type": "custom" }] },
|
||||
"onCopy": { "actions": [{ "id": "copy-json", "type": "custom" }] },
|
||||
"onPreview": { "actions": [{ "id": "open-preview", "type": "open-dialog", "target": "preview" }] },
|
||||
"onPreview": { "actions": [{ "id": "open-preview", "type": "open-dialog", "target": "uiState", "path": "preview" }] },
|
||||
"onClear": { "actions": [{ "id": "clear-schema", "type": "set-value", "target": "schema.components", "value": [] }] }
|
||||
}
|
||||
}
|
||||
@@ -177,6 +177,8 @@ The JSON UI system already supports `events` for action execution and `bindings`
|
||||
|
||||
**Why:** these are pure event triggers; `custom` actions cover app-specific flows that aren’t part of the built-in action types.
|
||||
|
||||
**Dialog storage convention:** `open-dialog`/`close-dialog` actions store booleans in `uiState.dialogs.<dialogId>`. Use `target` for the data source (typically `uiState`) and `path` for the dialog id.
|
||||
|
||||
### 5) Drag-and-drop/hover state (CanvasRenderer, ComponentTree)
|
||||
**Bindings:** IDs and `dropPosition` stored in data; events mapped to custom actions for editor logic.
|
||||
|
||||
@@ -229,7 +231,7 @@ The JSON UI system already supports `events` for action execution and `bindings`
|
||||
},
|
||||
"onEdit": {
|
||||
"actions": [
|
||||
{ "id": "open-source-editor", "type": "open-dialog", "target": "dataSourceEditor" }
|
||||
{ "id": "open-source-editor", "type": "open-dialog", "target": "uiState", "path": "dataSourceEditor" }
|
||||
]
|
||||
},
|
||||
"onDelete": {
|
||||
|
||||
@@ -4,11 +4,43 @@ import { Action, JSONUIContext } from '@/types/json-ui'
|
||||
import { evaluateExpression, evaluateTemplate } from '@/lib/json-ui/expression-evaluator'
|
||||
|
||||
export function useActionExecutor(context: JSONUIContext) {
|
||||
const { data, updateData, executeAction: contextExecute } = context
|
||||
const { data, updateData, updatePath, executeAction: contextExecute } = context
|
||||
|
||||
const executeAction = useCallback(async (action: Action, event?: any) => {
|
||||
try {
|
||||
const evaluationContext = { data, event }
|
||||
const updateByPath = (sourceId: string, path: string, value: any) => {
|
||||
if (updatePath) {
|
||||
updatePath(sourceId, path, value)
|
||||
return
|
||||
}
|
||||
|
||||
const sourceData = data[sourceId] ?? {}
|
||||
const pathParts = path.split('.')
|
||||
const newData = { ...sourceData }
|
||||
let current: any = newData
|
||||
|
||||
for (let i = 0; i < pathParts.length - 1; i++) {
|
||||
const key = pathParts[i]
|
||||
current[key] = typeof current[key] === 'object' && current[key] !== null ? { ...current[key] } : {}
|
||||
current = current[key]
|
||||
}
|
||||
|
||||
current[pathParts[pathParts.length - 1]] = value
|
||||
updateData(sourceId, newData)
|
||||
}
|
||||
|
||||
const resolveDialogTarget = () => {
|
||||
const defaultSourceId = 'uiState'
|
||||
const hasExplicitTarget = Boolean(action.target && action.path)
|
||||
const sourceId = hasExplicitTarget ? action.target : defaultSourceId
|
||||
const dialogId = action.path ?? action.target
|
||||
|
||||
if (!dialogId) return null
|
||||
|
||||
const dialogPath = dialogId.startsWith('dialogs.') ? dialogId : `dialogs.${dialogId}`
|
||||
return { sourceId, dialogPath }
|
||||
}
|
||||
|
||||
switch (action.type) {
|
||||
case 'create': {
|
||||
@@ -134,6 +166,20 @@ export function useActionExecutor(context: JSONUIContext) {
|
||||
break
|
||||
}
|
||||
|
||||
case 'open-dialog': {
|
||||
const dialogTarget = resolveDialogTarget()
|
||||
if (!dialogTarget) return
|
||||
updateByPath(dialogTarget.sourceId, dialogTarget.dialogPath, true)
|
||||
break
|
||||
}
|
||||
|
||||
case 'close-dialog': {
|
||||
const dialogTarget = resolveDialogTarget()
|
||||
if (!dialogTarget) return
|
||||
updateByPath(dialogTarget.sourceId, dialogTarget.dialogPath, false)
|
||||
break
|
||||
}
|
||||
|
||||
case 'custom': {
|
||||
if (contextExecute) {
|
||||
await contextExecute(action, event)
|
||||
@@ -145,7 +191,7 @@ export function useActionExecutor(context: JSONUIContext) {
|
||||
console.error('Action execution failed:', error)
|
||||
toast.error('Action failed')
|
||||
}
|
||||
}, [data, updateData, contextExecute])
|
||||
}, [data, updateData, updatePath, contextExecute])
|
||||
|
||||
const executeActions = useCallback(async (actions: Action[], event?: any) => {
|
||||
for (const action of actions) {
|
||||
|
||||
@@ -17,6 +17,7 @@ export function PageRenderer({ schema, onCustomAction }: PageRendererProps) {
|
||||
const context = {
|
||||
data,
|
||||
updateData,
|
||||
updatePath,
|
||||
executeAction: onCustomAction || (async () => {}),
|
||||
}
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ export interface PageSchema {
|
||||
export interface JSONUIContext {
|
||||
data: Record<string, any>
|
||||
updateData: (sourceId: string, value: any) => void
|
||||
updatePath?: (sourceId: string, path: string, value: any) => void
|
||||
executeAction: (action: Action, event?: any) => Promise<void>
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user