2dad2785 by Ean Schuessler

Fix screen rendering broken by transition support refactoring

- Revert to CustomScreenTestImpl instead of broken ec.screen.render() call
- Remove duplicate screenUrl variable declaration
- Fix transition method calls: hasTransitions() → hasTransition(null), getAllTransitions() → getTransitionList()
- Simplify rendering path to always use CustomScreenTestImpl for both action and browse modes

This restores working screen rendering functionality that was broken during the
action execution implementation work (commit 0fc4e236). The ec.screen.render()
API doesn't exist on ScreenFacadeImpl, causing RENDER_EXCEPTION for all screens.
1 parent b54f0e3c
...@@ -640,7 +640,6 @@ def startTime = System.currentTimeMillis() ...@@ -640,7 +640,6 @@ def startTime = System.currentTimeMillis()
640 try { 640 try {
641 ec.logger.info("MCP Screen Execution: Attempting to render screen ${screenPath} using ScreenTest with proper root screen, action=${parameters?.action}") 641 ec.logger.info("MCP Screen Execution: Attempting to render screen ${screenPath} using ScreenTest with proper root screen, action=${parameters?.action}")
642 642
643 // For ScreenTest to work properly, we need to use correct root screen
644 def testScreenPath = screenPath 643 def testScreenPath = screenPath
645 def rootScreen = "component://webroot/screen/webroot.xml" 644 def rootScreen = "component://webroot/screen/webroot.xml"
646 645
...@@ -694,30 +693,79 @@ def startTime = System.currentTimeMillis() ...@@ -694,30 +693,79 @@ def startTime = System.currentTimeMillis()
694 testScreenPath = "" 693 testScreenPath = ""
695 } 694 }
696 695
697 // Regular screen rendering with current user context - use real rendering if action is being processed 696 // Get final screen definition for MCP data extraction
698 def screenTest = null 697 def finalScreenDef = rootScreen ? ec.screen.getScreenDefinition(rootScreen) : null
699 def screenUrl = "http://localhost:8080/${screenPath}" 698 if (finalScreenDef && testScreenPath) {
699 // Navigate to subscreen
700 def pathSegments = testScreenPath.split('/')
701 for (segment in pathSegments) {
702 if (finalScreenDef) {
703 def subItem = finalScreenDef?.getSubscreensItem(segment)
704 if (subItem && subItem.getLocation()) {
705 finalScreenDef = ec.screen.getScreenDefinition(subItem.getLocation())
706 } else {
707 break
708 }
709 }
710 }
711 }
700 712
701 if (isActionExecution) { 713 // Extract MCP-specific data when renderMode is "mcp"
702 // Action is being processed - use real screen rendering with database access 714 if (renderMode == "mcp" && finalScreenDef) {
703 ec.logger.info("MCP Screen Execution: Action detected, using real screen rendering for ${screenPath}") 715 ec.logger.info("MCP Screen Execution: Extracting MCP data for ${screenPath}")
704 screenTest = ec.screen.makeTestScreen()
705 .rootScreen(rootScreen)
706 .renderMode(renderMode ? renderMode : "mcp")
707 .auth(ec.user.username)
708 716
709 def renderParams = parameters ?: [:] 717 // Extract parameters
710 renderParams.userId = ec.user.userId 718 if (finalScreenDef.parameterByName) {
711 renderParams.username = ec.user.username 719 mcpData.parameters = [:]
720 finalScreenDef.parameterByName.each { name, param ->
721 def value = ec.context.get(name) ?: parameters?.get(name)
722 mcpData.parameters[name] = [name: name, value: value, type: "parameter"]
723 }
724 }
712 725
713 def relativePath = subscreenName ? subscreenName.replaceAll('_','/') : testScreenPath 726 // Extract forms and their fields
714 ec.logger.info("REALRENDER root=${rootScreen} path=${relativePath} params=${renderParams}") 727 if (finalScreenDef.formByName) {
728 mcpData.forms = []
729 finalScreenDef.formByName.each { formName, form ->
730 def formInfo = [name: formName, fields: []]
731 def formNode = form.internalFormNode
732 if (formNode) {
733 // Extract field elements
734 def fields = formNode.'field'
735 fields.each { field ->
736 def fieldName = field.attribute('name')
737 if (fieldName) {
738 def fieldInfo = [name: fieldName, type: field.name()]
739 def value = ec.context.get(fieldName) ?: parameters?.get(fieldName)
740 if (value) fieldInfo.value = value
715 741
716 def realRender = screenTest.render(relativePath, renderParams, "POST") 742 // Check if it's a widget with options
717 } else { 743 if (field.'drop-down' || field.'check' || field.'radio') {
718 // Regular browse - use ScreenTest mock 744 fieldInfo.widgetType = "selection"
719 ec.logger.info("MCP Screen Execution: No action detected, using ScreenTest mock") 745 }
720 screenTest = new org.moqui.mcp.CustomScreenTestImpl(ec.ecfi) 746 formInfo.fields << fieldInfo
747 }
748 }
749 }
750 if (formInfo.fields) mcpData.forms << formInfo
751 }
752 }
753
754 // Extract transitions (actions like "Update" buttons)
755 if (finalScreenDef.hasTransition(null)) {
756 mcpData.actions = []
757 finalScreenDef.getTransitionList().each { trans ->
758 mcpData.actions << [
759 name: trans.name,
760 service: trans.xmlTransition ? trans.xmlTransition.attribute('service') : null,
761 description: trans.description
762 ]
763 }
764 }
765 }
766
767 // Regular screen rendering with current user context - use our custom ScreenTestImpl
768 def screenTest = new org.moqui.mcp.CustomScreenTestImpl(ec.ecfi)
721 .rootScreen(rootScreen) 769 .rootScreen(rootScreen)
722 .renderMode(renderMode ? renderMode : "mcp") 770 .renderMode(renderMode ? renderMode : "mcp")
723 .auth(ec.user.username) 771 .auth(ec.user.username)
...@@ -741,8 +789,27 @@ def startTime = System.currentTimeMillis() ...@@ -741,8 +789,27 @@ def startTime = System.currentTimeMillis()
741 789
742 def executionTime = (System.currentTimeMillis() - startTime) / 1000.0 790 def executionTime = (System.currentTimeMillis() - startTime) / 1000.0
743 791
744 // Add screen HTML as main content 792 // Build result based on renderMode
745 def content = [] 793 def content = []
794 if (renderMode == "mcp" && mcpData) {
795 // Return structured MCP data
796 def mcpResult = [
797 screenPath: screenPath,
798 screenUrl: screenUrl,
799 executionTime: executionTime,
800 isError: isError
801 ]
802 if (mcpData.parameters) mcpResult.parameters = mcpData.parameters
803 if (mcpData.forms) mcpResult.forms = mcpData.forms
804 if (mcpData.actions) mcpResult.actions = mcpData.actions
805 if (output) mcpResult.htmlPreview = output.take(2000) + (output.length() > 2000 ? "..." : "")
806
807 content << [
808 type: "text",
809 text: new groovy.json.JsonBuilder(mcpResult).toString()
810 ]
811 } else {
812 // Return raw output for other modes
746 content << [ 813 content << [
747 type: "text", 814 type: "text",
748 text: output, 815 text: output,
...@@ -751,6 +818,7 @@ def startTime = System.currentTimeMillis() ...@@ -751,6 +818,7 @@ def startTime = System.currentTimeMillis()
751 executionTime: executionTime, 818 executionTime: executionTime,
752 isError: isError 819 isError: isError
753 ] 820 ]
821 }
754 822
755 result = [ 823 result = [
756 content: content, 824 content: content,
...@@ -1130,10 +1198,10 @@ def startTime = System.currentTimeMillis() ...@@ -1130,10 +1198,10 @@ def startTime = System.currentTimeMillis()
1130 message: "Form parameters submitted", 1198 message: "Form parameters submitted",
1131 parametersProcessed: actionParams.keySet() 1199 parametersProcessed: actionParams.keySet()
1132 ] 1200 ]
1133 } else if (screenDef && screenDef.transitions) { 1201 } else if (screenDef && screenDef.hasTransitions()) {
1134 // Look for matching transition by name 1202 // Look for matching transition by name
1135 for (def transition : screenDef.transitions) { 1203 for (def transition : screenDef.getAllTransitions()) {
1136 if (transition.@name == action) { 1204 if (transition.name == action) {
1137 foundTransition = transition 1205 foundTransition = transition
1138 break 1206 break
1139 } 1207 }
......