You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ofbiz.apache.org by nm...@apache.org on 2020/01/09 16:51:39 UTC

[ofbiz-framework] branch trunk updated: Implemented: REST, adding segmented URI support for webtools/entitymaint (OFBIZ-11007)

This is an automated email from the ASF dual-hosted git repository.

nmalin pushed a commit to branch trunk
in repository https://gitbox.apache.org/repos/asf/ofbiz-framework.git


The following commit(s) were added to refs/heads/trunk by this push:
     new 6e1c7b5  Implemented: REST, adding segmented URI support for webtools/entitymaint (OFBIZ-11007)
6e1c7b5 is described below

commit 6e1c7b5958cc1a80be5746bfd177136a1feabe0d
Author: Nicolas Malin <ni...@nereide.fr>
AuthorDate: Thu Jan 9 17:51:12 2020 +0100

    Implemented: REST, adding segmented URI support for webtools/entitymaint
    (OFBIZ-11007)
    
    After implemeted Rest mechanism on rev. 1868963 by Mathieu Lirzin,
    I reviewed the rest url implemented by Artemiy Rozovyk for entitymaint in webtools.
    
    With discussion with Mathieu and Leila, I selected this pattern :
    
        entity/[cover]/{entityName}/{pkValues: .*}
    
    and implemented like this :
    
        entity/list -> list all entities
        entity/find/Party -> search
        entity/find/Party/Company -> displaying form for Party with id Company
        entity/create/Party -> creation form for a Party
        entity/edit/Party/Company/Company -> edit form for Party with id Company
        entity/change/Party/Company -> call crud following given http method
        entity/relations/Party -> View relation for Party
    
    The old uris were currently kept and the oldest GenericWebEvent.updateGeneric() were updated to support rest method information.
    
    Thanks Mathieu, Artemiy and Leila for their help to complete this improvement.
---
 .../webtools/config/WebtoolsErrorUiLabels.xml      |  4 ++
 .../groovyScripts/entity/FindGeneric.groovy        | 17 ++++++---
 .../groovyScripts/entity/ViewGeneric.groovy        | 31 ++++++++-------
 .../org/apache/ofbiz/webtools/GenericWebEvent.java | 16 +++++++-
 .../template/artifactinfo/ArtifactInfo.ftl         |  2 +-
 framework/webtools/template/entity/EntityMaint.ftl | 22 ++++-------
 .../webtools/template/entity/EntityRefMain.ftl     |  2 +-
 framework/webtools/template/entity/ViewGeneric.ftl | 22 +++++++----
 .../webtools/template/entity/ViewRelations.ftl     |  4 +-
 .../webapp/webtools/WEB-INF/controller.xml         | 44 ++++++++++++++++++++++
 framework/webtools/widget/EntityForms.xml          |  4 +-
 framework/webtools/widget/EntityScreens.xml        | 21 +++++++----
 framework/webtools/widget/Menus.xml                | 12 ++----
 13 files changed, 134 insertions(+), 67 deletions(-)

diff --git a/framework/webtools/config/WebtoolsErrorUiLabels.xml b/framework/webtools/config/WebtoolsErrorUiLabels.xml
index 665a0ca..4ffb96f 100644
--- a/framework/webtools/config/WebtoolsErrorUiLabels.xml
+++ b/framework/webtools/config/WebtoolsErrorUiLabels.xml
@@ -100,6 +100,10 @@
         <value xml:lang="zh">无法删除(写错误)</value>
         <value xml:lang="zh-TW">無法刪除(寫錯誤)</value>
     </property>
+    <property key="genericWebEvent.delete_succeeded">
+        <value xml:lang="en">Delete succeeded</value>
+        <value xml:lang="fr">La suppression a été effectuée: </value>
+    </property>
     <property key="genericWebEvent.entity_name_not_specified">
         <value xml:lang="en">The entityName was not specified, but is required</value>
         <value xml:lang="es">El nombre de la entidad no fue especificado, pero es requerido</value>
diff --git a/framework/webtools/groovyScripts/entity/FindGeneric.groovy b/framework/webtools/groovyScripts/entity/FindGeneric.groovy
index 11bbacb..29d3eb1 100644
--- a/framework/webtools/groovyScripts/entity/FindGeneric.groovy
+++ b/framework/webtools/groovyScripts/entity/FindGeneric.groovy
@@ -41,8 +41,9 @@ if (modelEntity) {
     ModelReader entityModelReader = delegator.getModelReader()
     //create the search form with auto-fields-entity
     String dynamicAutoEntityFieldSearchForm = """<?xml version="1.0" encoding="UTF-8"?><forms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ofbiz.apache.org/Widget-Form" xsi:schemaLocation="http://ofbiz.apache.org/Widget-Form http://ofbiz.apache.org/dtds/widget-form.xsd">
-        <form name="FindGeneric" type="single" target="FindGeneric?entityName=${entityName}">
+        <form name="FindGeneric" type="single" target="entity/find/${entityName}">
            <auto-fields-entity entity-name="${entityName}" default-field-type="find" include-internal="true"/>
+            <field name="restMethod"><hidden value="GET"/></field>
             <field name="noConditionFind"><hidden value="Y"/></field>
             <field name="searchOptions_collapsed" ><hidden value="true"/></field>
             <field name="searchButton"><submit/></field>"""
@@ -81,9 +82,16 @@ if (modelEntity) {
     dynamicAutoEntitySearchFormRenderer.render(writer, context)
     context.dynamicAutoEntitySearchForm = writer
 
+    // In case of composite pk
+    String pk = modelEntity.pkNameString()
+    String res = ""
+    for (w in pk.split(", ")) {
+        res = "${res}/\${${w}}"
+    }
+
     //prepare the result list from performFind
     String dynamicAutoEntityFieldListForm = """<?xml version="1.0" encoding="UTF-8"?><forms xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://ofbiz.apache.org/Widget-Form" xsi:schemaLocation="http://ofbiz.apache.org/Widget-Form http://ofbiz.apache.org/dtds/widget-form.xsd">
-            <form name="ListGeneric" type="list" target="FindGeneric" list-name="listIt" 
+            <form name="ListGeneric" type="list" method="post" target="entity/find/${entityName}" list-name="listIt" 
               odd-row-style="alternate-row" default-table-style="basic-table light-grid hover-bar" header-row-style="header-row-2">
             <actions>
                 <service service-name="performFind">
@@ -100,10 +108,7 @@ if (modelEntity) {
                     "<field name=\"${modelField.name}\" sort-field=\"true\"/>"
     }
     dynamicAutoEntityFieldListForm += """
-            <field name="viewGeneric" title=" "><hyperlink target="ViewGeneric" description="view">
-                <auto-parameters-entity entity-name="${entityName}"/>
-                <parameter param-name="entityName" value="${entityName}"/>
-            </hyperlink></field>
+            <field name="viewGeneric" title=" "><hyperlink target="entity/find/${entityName}${res}" description="view"/></field>
             <sort-order><sort-field name="viewGeneric"/></sort-order>
             </form></forms>"""
 
diff --git a/framework/webtools/groovyScripts/entity/ViewGeneric.groovy b/framework/webtools/groovyScripts/entity/ViewGeneric.groovy
index ea9c05b..36c963d 100644
--- a/framework/webtools/groovyScripts/entity/ViewGeneric.groovy
+++ b/framework/webtools/groovyScripts/entity/ViewGeneric.groovy
@@ -28,7 +28,6 @@ import org.apache.ofbiz.entity.model.ModelRelation
 import org.apache.ofbiz.entity.model.ModelKeyMap
 import org.apache.ofbiz.base.util.UtilFormatOut
 import org.apache.ofbiz.base.util.UtilMisc
-import org.apache.ofbiz.base.util.UtilValidate
 import java.sql.Timestamp
 import java.sql.Date
 import java.sql.Time
@@ -58,25 +57,31 @@ context.put("hasAllDelete", hasAllDelete)
 context.put("hasViewPermission", hasViewPermission)
 context.put("hasCreatePermission", hasCreatePermission)
 context.put("hasUpdatePermission", hasUpdatePermission)
-context.put("hasDeletePermission" , hasDeletePermission)
+context.hasDeletePermission = hasDeletePermission
 
 boolean useValue = true
-String curFindString = "entityName=" + entityName
+String currentFindString = entityName
 GenericPK findByPK = delegator.makePK(entityName)
 Iterator pkIterator = entity.getPksIterator()
-while (pkIterator.hasNext()) {
-    ModelField field = pkIterator.next()
-    ModelFieldType type = delegator.getEntityFieldType(entity, field.getType())
-    String fval = parameters.get(field.getName())
-    if (fval) {
-        curFindString = curFindString + "&" + field.getName() + "=" + fval
-        findByPK.setString(field.getName(), fval)
+String fieldValues = parameters.get("pkValues")
+HashMap<String,String> pkNamesValuesMap = new HashMap<>()
+if (fieldValues != null) {
+    Iterator pkParamIterator = Arrays.asList(fieldValues.split("/")).iterator()
+    while (pkIterator.hasNext() && pkParamIterator.hasNext()) {
+        ModelField field = pkIterator.next()
+        String fieldValue = pkParamIterator.next()
+        if (fieldValue) {
+            currentFindString += "/" + fieldValue
+            pkNamesValuesMap[field.getName()] = fieldValue
+            findByPK.setString(field.getName(), fieldValue)
+        }
     }
 }
+parameters << pkNamesValuesMap
+context.pkNamesValuesMap = pkNamesValuesMap
 context.put("findByPk", findByPK.toString())
 
-curFindString = UtilFormatOut.encodeQuery(curFindString)
-context.put("curFindString", curFindString)
+context.currentFindString = UtilFormatOut.encodeQuery(currentFindString)
 
 GenericValue value = null
 //only try to find it if this is a valid primary key...
@@ -136,7 +141,7 @@ if (value == null && (findByPK.getAllFields().size() > 0)) {
 }
 context.put("pkNotFound", pkNotFound)
 
-String lastUpdateMode = parameters.get("UPDATE_MODE")
+String lastUpdateMode = parameters.get("restMethod")
 if ((session.getAttribute("_ERROR_MESSAGE_") != null || request.getAttribute("_ERROR_MESSAGE_") != null) &&
     lastUpdateMode != null && !"DELETE".equals(lastUpdateMode)) {
     //if we are updating and there is an error, do not use the entity data for the fields, use parameters to get the old value
diff --git a/framework/webtools/src/main/java/org/apache/ofbiz/webtools/GenericWebEvent.java b/framework/webtools/src/main/java/org/apache/ofbiz/webtools/GenericWebEvent.java
index 635c782..11e7736 100644
--- a/framework/webtools/src/main/java/org/apache/ofbiz/webtools/GenericWebEvent.java
+++ b/framework/webtools/src/main/java/org/apache/ofbiz/webtools/GenericWebEvent.java
@@ -61,7 +61,9 @@ public class GenericWebEvent {
     public static String updateGeneric(HttpServletRequest request, HttpServletResponse response) {
         String entityName = request.getParameter("entityName");
         Locale locale = UtilHttp.getLocale(request);
-
+        if (UtilValidate.isEmpty(entityName)) {
+            entityName = (String) request.getAttribute("entityName");
+        }
         if (UtilValidate.isEmpty(entityName)) {
             String errMsg = UtilProperties.getMessage(GenericWebEvent.err_resource, "genericWebEvent.entity_name_not_specified", locale) + ".";
             request.setAttribute("_ERROR_MESSAGE_", errMsg);
@@ -95,6 +97,16 @@ public class GenericWebEvent {
         }
 
         String updateMode = request.getParameter("UPDATE_MODE");
+        if (updateMode == null && request.getParameter("restMethod") == null) {
+            updateMode = "CREATE";
+        }
+        if (updateMode == null) {
+            switch (request.getParameter("restMethod")) {
+                case "PUT": updateMode = "UPDATE"; break;
+                case "DELETE": updateMode = "DELETE"; break;
+                default: updateMode = "CREATE"; break;
+            }
+        }
 
         if (UtilValidate.isEmpty(updateMode)) {
             String errMsg = UtilProperties.getMessage(GenericWebEvent.err_resource, "genericWebEvent.update_mode_not_specified", locale) + ".";
@@ -156,6 +168,8 @@ public class GenericWebEvent {
             // Delete actual main entity last, just in case database is set up to do a cascading delete, caches won't get cleared
             try {
                 delegator.removeByPrimaryKey(findByEntity.getPrimaryKey());
+                String confirmMsg = UtilProperties.getMessage(GenericWebEvent.err_resource, "genericWebEvent.delete_succeeded", locale) ;
+                request.setAttribute("_EVENT_MESSAGE_", confirmMsg);
             } catch (GenericEntityException e) {
                 String errMsg = UtilProperties.getMessage(GenericWebEvent.err_resource, "genericWebEvent.delete_failed", locale) + ": " + e.toString();
                 Debug.logWarning(e, errMsg, module);
diff --git a/framework/webtools/template/artifactinfo/ArtifactInfo.ftl b/framework/webtools/template/artifactinfo/ArtifactInfo.ftl
index 0a900b0..7c4496f 100644
--- a/framework/webtools/template/artifactinfo/ArtifactInfo.ftl
+++ b/framework/webtools/template/artifactinfo/ArtifactInfo.ftl
@@ -127,7 +127,7 @@ under the License.
     </#if>
 
     <#if "entity" == artifactInfo.getType()>
-        <div><a href="<@o...@ofbizUrl>">All Entity Data</a></div>
+        <div><a href="<@o...@ofbizUrl>">All Entity Data</a></div>
         <h2>Entity Fields</h2>
         <table>
         <#list artifactInfo.modelEntity.getFieldsUnmodifiable() as modelField>
diff --git a/framework/webtools/template/entity/EntityMaint.ftl b/framework/webtools/template/entity/EntityMaint.ftl
index 3da728e..c12f42b 100644
--- a/framework/webtools/template/entity/EntityMaint.ftl
+++ b/framework/webtools/template/entity/EntityMaint.ftl
@@ -79,21 +79,13 @@ under the License.
             <td<#if anchor?has_content> ${anchor}</#if>>${entity.entityName}<#if entity.viewEntity == 'Y'>&nbsp;(${uiLabelMap.WebtoolsEntityView})</#if></td>
             <#assign anchor="">
             <td class="button-col">
-              <#if entity.viewEntity == 'Y'>
-                <#if entity.entityPermissionView == 'Y'>
-                  <a href='<@o...@ofbizUrl>'>${uiLabelMap.WebtoolsReln}</a>
-                  <a href='<@o...@ofbizUrl>'>${uiLabelMap.WebtoolsFind}</a>
-                  <a href='<@o...@ofbizUrl>'>${uiLabelMap.WebtoolsAll}</a>
-                </#if>
-              <#else>
-                <#if entity.entityPermissionCreate == 'Y'>
-                  <a href='<@o...@ofbizUrl>' title='${uiLabelMap.CommonCreate}'>${uiLabelMap.WebtoolsCreate}</a>
-                </#if>
-                <#if entity.entityPermissionView == 'Y'>
-                  <a href='<@o...@ofbizUrl>' title='${uiLabelMap.WebtoolsViewRelations}'>${uiLabelMap.WebtoolsReln}</a>
-                  <a href='<@o...@ofbizUrl>' title='${uiLabelMap.WebtoolsFindRecord}'>${uiLabelMap.WebtoolsFind}</a>
-                  <a href='<@o...@ofbizUrl>' title='${uiLabelMap.WebtoolsFindAllRecords}'>${uiLabelMap.WebtoolsAll}</a>
-                </#if>
+              <#if entity.viewEntity != 'Y' && entity.entityPermissionCreate == 'Y'>
+                <a href='<@o...@ofbizUrl>' title='${uiLabelMap.CommonCreate}'>${uiLabelMap.WebtoolsCreate}</a>
+              </#if>
+              <#if entity.entityPermissionView == 'Y'>
+                <a href='<@o...@ofbizUrl>'>${uiLabelMap.WebtoolsReln}</a>
+                <a href='<@o...@ofbizUrl>'>${uiLabelMap.WebtoolsFind}</a>
+                <a href='<@o...@ofbizUrl>'>${uiLabelMap.WebtoolsAll}</a>
               </#if>
             </td>
             <#if right_col>
diff --git a/framework/webtools/template/entity/EntityRefMain.ftl b/framework/webtools/template/entity/EntityRefMain.ftl
index dbebc7d..7267c13 100644
--- a/framework/webtools/template/entity/EntityRefMain.ftl
+++ b/framework/webtools/template/entity/EntityRefMain.ftl
@@ -63,7 +63,7 @@ under the License.
                             </div>
                             <div>${entity.title}&nbsp;
                                 <#if !forstatic>
-                                    <a target='main' href="<@o...@ofbizUrl>">[${uiLabelMap.WebtoolsViewData}]</a>
+                                    <a target='main' href="<@o...@ofbizUrl>">[${uiLabelMap.WebtoolsViewData}]</a>
                                 </#if>
                                 <#if !forstatic>
                                     <a target='main' href="<@o...@ofbizUrl>">[${uiLabelMap.WebtoolsArtifactInfo}]</a>
diff --git a/framework/webtools/template/entity/ViewGeneric.ftl b/framework/webtools/template/entity/ViewGeneric.ftl
index 6ee882f..216eb63 100644
--- a/framework/webtools/template/entity/ViewGeneric.ftl
+++ b/framework/webtools/template/entity/ViewGeneric.ftl
@@ -50,15 +50,22 @@ function ShowTab(lname) {
     <h2>${uiLabelMap.WebtoolsWithPk}: ${findByPk}</h2>
     <br />
     <div class="button-bar">
-      <a href='<@o...@ofbizUrl>' class="buttontext">${uiLabelMap.WebtoolsBackToFindScreen}</a>
+      <a href='<@o...@ofbizUrl>' class="buttontext">${uiLabelMap.WebtoolsBackToFindScreen}</a>
       <#if enableEdit = "false">
         <#if hasCreatePermission>
-          <a href='<@o...@ofbizUrl>' class="buttontext create">${uiLabelMap.CommonCreate}</a>
-          <a href="<@o...@ofbizUrl>" class="buttontext">${uiLabelMap.CommonEdit}</a>
+          <form action="<@o...@ofbizUrl>" method="get">
+            <input type="submit" value="${uiLabelMap.CommonEdit}" />
+          </form>
         </#if>
         <#if value?has_content>
           <#if hasDeletePermission>
-            <a href='<@o...@ofbizUrl>' class="buttontext delete">${uiLabelMap.WebtoolsDeleteThisValue}</a>
+            <form action='<@o...@ofbizUrl>' method="delete" name="updateForm">
+              <input type="hidden" value="DELETE" name="restMethod"/>
+              <#list pkNamesValuesMap.keySet() as pkName>
+                <input type="hidden" value="${pkNamesValuesMap.get(pkName)}" name="${pkName}"/>
+              </#list>
+              <input type="submit" value="${uiLabelMap.WebtoolsDeleteThisValue}" />
+            </form>
           </#if>
         </#if>
       </#if>
@@ -104,14 +111,13 @@ function ShowTab(lname) {
           <#if pkNotFound>
             <p>${uiLabelMap.WebtoolsEntityName} ${entityName} ${uiLabelMap.WebtoolsWithPk} ${findByPk} ${uiLabelMap.WebtoolsSpecifiedEntity2}.</p>
           </#if>
-          <form action='<@o...@ofbizUrl>' method="post" name="updateForm">
+          <form action='<@ofbizUrl>entity/change/<#if value?has_content>${currentFindString}<#e...@ofbizUrl>' method="post" name="updateForm">
             <#assign showFields = true>
             <#assign alt_row = false>
             <table class="basic-table" cellspacing="0">
               <#if value?has_content>
                 <#if hasUpdatePermission>
                   <#if newFieldPkList?has_content>
-                    <input type="hidden" name="UPDATE_MODE" value="UPDATE"/>
                     <#list newFieldPkList as field>
                       <tr<#if alt_row> class="alternate-row"</#if>>
                         <td class="label">${field.name}</td>
@@ -131,7 +137,6 @@ function ShowTab(lname) {
                 <#if hasCreatePermission>
                   <#if newFieldPkList?has_content>
                     <p>${uiLabelMap.WebtoolsYouMayCreateAnEntity}</p>
-                    <input type="hidden" name="UPDATE_MODE" value="CREATE"/>
                     <#list newFieldPkList as field>
                       <tr<#if alt_row> class="alternate-row"</#if>>
                         <td class="label">${field.name}</td>
@@ -204,6 +209,7 @@ function ShowTab(lname) {
                     <#assign alt_row = !alt_row>
                   </#list>
                   <#if value?has_content>
+                    <input type="hidden" name="restMethod" value="PUT"/>
                     <#assign button = "${uiLabelMap.CommonUpdate}">
                   <#else>
                     <#assign button = "${uiLabelMap.CommonCreate}">
@@ -212,7 +218,7 @@ function ShowTab(lname) {
                     <td>&nbsp;</td>
                     <td>
                       <input type="submit" name="Update" value="${button}" />
-                      <a href="<@o...@ofbizUrl>" class="smallSubmit">${uiLabelMap.CommonCancel}</a>
+                      <a href="<@o...@ofbizUrl>" class="smallSubmit">${uiLabelMap.CommonCancel}</a>
                     </td>
                   </tr>
                 </#if>
diff --git a/framework/webtools/template/entity/ViewRelations.ftl b/framework/webtools/template/entity/ViewRelations.ftl
index 5581983..00dfd03 100644
--- a/framework/webtools/template/entity/ViewRelations.ftl
+++ b/framework/webtools/template/entity/ViewRelations.ftl
@@ -29,7 +29,7 @@ under the License.
         <h2>${uiLabelMap.WebtoolsForEntity}: ${entityName}</h2>
         <br />
         <div class="button-bar">
-            <a href="<@o...@ofbizUrl>" class="smallSubmit">${uiLabelMap.WebtoolsBackToFindScreen}</a>
+            <a href="<@o...@ofbizUrl>" class="smallSubmit">${uiLabelMap.WebtoolsBackToFindScreen}</a>
         </div>
         <br />
         <table class="basic-table hover-bar" cellspacing="0">
@@ -44,7 +44,7 @@ under the License.
             <#list relations as relation>
                 <tr<#if alt_row> class="alternate-row"</#if>>
                     <td>${relation.title}</td>
-                    <td class="button-col"><a href='<@o...@ofbizUrl>'>${relation.relEntityName}</a></td>
+                    <td class="button-col"><a href='<@o...@ofbizUrl>'>${relation.relEntityName}</a></td>
                     <td>${relation.type}</td>
                     <td>${relation.fkName}</td>
                     <td>
diff --git a/framework/webtools/webapp/webtools/WEB-INF/controller.xml b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
index eaec92b..6e4976c 100644
--- a/framework/webtools/webapp/webtools/WEB-INF/controller.xml
+++ b/framework/webtools/webapp/webtools/WEB-INF/controller.xml
@@ -42,6 +42,49 @@ under the License.
 
     <!-- Request Mappings -->
 
+    <!-- === Rest Entity Mapping === -->
+
+    <!-- form for creating a record  -->
+    <request-map uri="entity/list" method="get"><security https="true" auth="true"/><response name="success" type="view" value="entitymaint" /></request-map>
+
+    <!-- form for creating a record  -->
+    <request-map uri="entity/create/{entityName}" method="get"><security https="true" auth="true"/><response name="success" type="view" value="EditGeneric"/></request-map>
+
+    <!-- form for modifying a record  -->
+    <request-map uri="entity/edit/{entityName}/{pkValues: .*}" method="get"><security https="true" auth="true"/><response name="success" type="view" value="EditGeneric" /></request-map>
+
+    <!--view relations for a given entity -->
+    <request-map uri="entity/relations/{entityName}" method="get"><security https="true" auth="true"/><response name="success" type="view" value="ViewRelations" /></request-map>
+
+    <!-- getting the view of records -->
+    <request-map uri="entity/find/{entityName}" method="get"><security https="true" auth="true"/><response name="success" type="view" value="FindGeneric" /></request-map>
+
+    <!-- adding new record (from submitted form) -->
+    <request-map uri="entity/change/{entityName}" method="post">
+        <security https="true" auth="true"/>
+        <event type="java" path="org.apache.ofbiz.webtools.GenericWebEvent" invoke="updateGeneric"/>
+        <response name="success" type="view" value="FindGeneric"/>
+        <response name="error" type="view" value="ViewGeneric"/>
+    </request-map>
+
+    <!-- view entity records -->
+    <request-map uri="entity/find/{entityName}/{pkValues: .*}" method="get"><security https="true" auth="true"/><response name="success" type="view" value="ViewGeneric" /></request-map>
+
+    <!-- modifying existing record -->
+    <request-map uri="entity/change/{entityName}/{pkValues: .*}" method="put">
+        <security https="true" auth="true"/>
+        <event type="java" path="org.apache.ofbiz.webtools.GenericWebEvent" invoke="updateGeneric"/>
+        <response name="success" type="view" value="ViewGeneric"/>
+        <response name="error" type="view" value="ViewGeneric"/>
+    </request-map>
+    <!-- deleting existing record -->
+    <request-map uri="entity/change/{entityName}/{pkValues: .*}" method="delete">
+        <security https="true" auth="true"/>
+        <event type="java" path="org.apache.ofbiz.webtools.GenericWebEvent" invoke="updateGeneric"/>
+        <response name="success" type="view" value="ViewGeneric"/>
+        <response name="error" type="view" value="ViewGeneric"/>
+    </request-map>
+
     <!-- Begin Utility Requests -->
     <request-map uri="httpService">
         <event type="java" path="org.apache.ofbiz.service.engine.HttpEngine" invoke="httpEngine"/>
@@ -586,6 +629,7 @@ under the License.
     <view-map name="entitymaint" type="screen" page="component://webtools/widget/EntityScreens.xml#EntityMaint"/>
     <view-map name="FindGeneric" type="screen" page="component://webtools/widget/EntityScreens.xml#FindGeneric"/>
     <view-map name="ViewGeneric" type="screen" page="component://webtools/widget/EntityScreens.xml#ViewGeneric"/>
+    <view-map name="EditGeneric" type="screen" page="component://webtools/widget/EntityScreens.xml#EditGeneric"/>
     <view-map name="ViewRelations" type="screen" page="component://webtools/widget/EntityScreens.xml#ViewRelations"/>
 
     <!-- these are NOT regions because they generate text output that should never be decorated -->
diff --git a/framework/webtools/widget/EntityForms.xml b/framework/webtools/widget/EntityForms.xml
index 1587fea..9c37ee3 100644
--- a/framework/webtools/widget/EntityForms.xml
+++ b/framework/webtools/widget/EntityForms.xml
@@ -59,9 +59,7 @@ under the License.
             <set field="firstChar" value="${groovy: entityName.substring(0, 1)}"/>
         </row-actions>
         <field name="entityName">
-            <hyperlink id="${firstChar}" description="${entityName} ${groovy: if (viewEntity == 'Y') return '(' + uiLabelMap.WebtoolsEntityView + ')'}" target="FindGeneric">
-               <parameter param-name="entityName"/>
-            </hyperlink>
+            <hyperlink id="${firstChar}" description="${entityName} ${groovy: if (viewEntity == 'Y') return '(' + uiLabelMap.WebtoolsEntityView + ')'}" target="entity/find/${entityName}"/>
         </field>
         <field name="title"><display/></field>
         <field name="actions" title=" ">
diff --git a/framework/webtools/widget/EntityScreens.xml b/framework/webtools/widget/EntityScreens.xml
index d852704..0994a43 100644
--- a/framework/webtools/widget/EntityScreens.xml
+++ b/framework/webtools/widget/EntityScreens.xml
@@ -212,14 +212,9 @@ under the License.
                         <decorator-screen name="FindScreenDecorator" location="component://common/widget/CommonScreens.xml">
                             <decorator-section name="menu-bar">
                                 <container style="button-bar button-style-1">
-                                    <link target="entitymaint" text="${uiLabelMap.WebtoolsBackToEntityList}"/>
-                                    <link target="ViewRelations" text="${uiLabelMap.WebtoolsViewRelations}">
-                                        <parameter param-name="entityName"/>
-                                    </link>
-                                    <link target="ViewGeneric" text="${uiLabelMap.CommonCreate}" style="create">
-                                        <parameter param-name="entityName"/>
-                                        <parameter param-name="enableEdit" value="true"/>
-                                    </link>
+                                    <link target="entity/list" text="${uiLabelMap.WebtoolsBackToEntityList}"/>
+                                    <link target="entity/relations/${entityName}" text="${uiLabelMap.WebtoolsViewRelations}"/>
+                                    <link target="entity/create/${entityName}" text="${uiLabelMap.CommonCreate}" style="create"/>
                                 </container>
                             </decorator-section>
                             <decorator-section name="search-options">
@@ -266,6 +261,16 @@ under the License.
             </fail-widgets>
         </section>
     </screen>
+    <screen name="EditGeneric">
+        <section>
+            <actions>
+                <set field="parameters.enableEdit" value="true"/>
+            </actions>
+            <widgets>
+                <include-screen name="ViewGeneric"/>
+            </widgets>
+        </section>
+    </screen>
     <screen name="ViewRelations">
         <section>
             <condition>
diff --git a/framework/webtools/widget/Menus.xml b/framework/webtools/widget/Menus.xml
index 0dab587..2cf57d8 100644
--- a/framework/webtools/widget/Menus.xml
+++ b/framework/webtools/widget/Menus.xml
@@ -212,19 +212,13 @@ under the License.
                     <if-compare field="viewEntity" operator="not-equals" value="Y"/>
                 </and>
             </condition>
-            <link target="ViewGeneric" style="buttontext">
-                <parameter param-name="entityName"/>
-                <parameter param-name="enableEdit" value="true"/>
-            </link>
+            <link target="entity/create/${entityName}" style="buttontext"/>
         </menu-item>
         <menu-item name="relation" title="${uiLabelMap.WebtoolsReln}">
-            <link target="ViewRelations" style="buttontext">
-                <parameter param-name="entityName"/>
-            </link>
+            <link target="entity/relations/${entityName}" style="buttontext"/>
         </menu-item>
         <menu-item name="all" title="${uiLabelMap.WebtoolsAll}">
-            <link target="FindGeneric" style="buttontext">
-                <parameter param-name="entityName"/>
+            <link target="entity/find/${entityName}" style="buttontext">
                 <parameter param-name="noConditionFind" value="Y"/>
             </link>
         </menu-item>