From 0cd562000d8f849948a3283c0523be9fec18808b Mon Sep 17 00:00:00 2001
From: Sebastian Listl <s.listl@adito.de>
Date: Wed, 26 Aug 2020 16:25:19 +0200
Subject: [PATCH] #1064056 Sorting implementation for Attributes

---
 entity/Attribute_entity/Attribute_entity.aod  | 103 ++++++++++--
 .../attribute_parent_id/valueProcess.js       |   4 +-
 .../attribute_type/stateProcess.js            |   3 +-
 .../attribute_type/valueProcess.js            |   4 +-
 .../newchildattribute/onActionProcess.js      |   4 +-
 .../valueProcess.js                           |   3 +
 .../displaysimplename_param/valueProcess.js   |   3 +
 .../children/parentid_param/valueProcess.js   |   4 +
 .../children/parenttype_param/valueProcess.js |   4 +
 .../childattributes/stateProcess.js           |   6 +
 .../whitelistids_param/valueProcess.js        |   4 +-
 .../recordcontainers/jdito/contentProcess.js  | 146 +++++++++---------
 .../recordcontainers/jdito/onInsert.js        |  21 ++-
 .../entityfields/date_new/valueProcess.js     |   7 +-
 neonContext/Attribute/Attribute.aod           |   8 +
 .../AttributeEdit_view/AttributeEdit_view.aod |   5 +
 .../AttributeList_view/AttributeList_view.aod |  30 ++++
 .../AttributeMultiEdit_view.aod               |  30 ++++
 .../AttributePreview_view.aod                 |   5 +
 19 files changed, 295 insertions(+), 99 deletions(-)
 create mode 100644 entity/Attribute_entity/entityfields/attributechildren/children/getonlyfirstlevelchildren_param/valueProcess.js
 create mode 100644 entity/Attribute_entity/entityfields/childattributes/children/displaysimplename_param/valueProcess.js
 create mode 100644 entity/Attribute_entity/entityfields/childattributes/children/parentid_param/valueProcess.js
 create mode 100644 entity/Attribute_entity/entityfields/childattributes/children/parenttype_param/valueProcess.js
 create mode 100644 entity/Attribute_entity/entityfields/childattributes/stateProcess.js
 create mode 100644 neonView/AttributeList_view/AttributeList_view.aod
 create mode 100644 neonView/AttributeMultiEdit_view/AttributeMultiEdit_view.aod

diff --git a/entity/Attribute_entity/Attribute_entity.aod b/entity/Attribute_entity/Attribute_entity.aod
index 735588f943..d6f3d3eec9 100644
--- a/entity/Attribute_entity/Attribute_entity.aod
+++ b/entity/Attribute_entity/Attribute_entity.aod
@@ -180,10 +180,6 @@
           <name>ChildType_param</name>
           <expose v="false" />
         </entityParameter>
-        <entityParameter>
-          <name>ParentIdPreset_param</name>
-          <expose v="false" />
-        </entityParameter>
       </children>
     </entityProvider>
     <entityField>
@@ -218,6 +214,18 @@
           <name>ParentId_param</name>
           <expose v="false" />
         </entityParameter>
+        <entityParameter>
+          <name>AttributeCount_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>IncludeParentRecord_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>ObjectType_param</name>
+          <expose v="false" />
+        </entityParameter>
       </children>
     </entityProvider>
     <entityConsumer>
@@ -367,10 +375,6 @@
           <name>ParentId_param</name>
           <expose v="false" />
         </entityParameter>
-        <entityParameter>
-          <name>ParentIdPreset_param</name>
-          <expose v="false" />
-        </entityParameter>
       </children>
     </entityProvider>
     <entityParameter>
@@ -379,14 +383,89 @@
       <description>parent id, this is used for filtering by the parent in the content process</description>
     </entityParameter>
     <entityParameter>
-      <name>ParentIdPreset_param</name>
+      <name>IncludeParentRecord_param</name>
+      <expose v="true" />
+      <documentation>%aditoprj%/entity/Attribute_entity/entityfields/includeparentrecord_param/documentation.adoc</documentation>
+    </entityParameter>
+    <entityProvider>
+      <name>AttributeChildren</name>
+      <sortingField>SORTING</sortingField>
+      <titlePlural>Child Attributes</titlePlural>
+      <dependencies>
+        <entityDependency>
+          <name>80023321-1954-483f-a4be-b7207557c068</name>
+          <entityName>Attribute_entity</entityName>
+          <fieldName>ChildAttributes</fieldName>
+          <isConsumer v="false" />
+        </entityDependency>
+      </dependencies>
+      <children>
+        <entityParameter>
+          <name>ChildId_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>AttributeCount_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>ChildType_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>FilteredAttributeIds_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>IncludeParentRecord_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>ObjectType_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>ThemeObjectRowId_param</name>
+          <expose v="false" />
+        </entityParameter>
+        <entityParameter>
+          <name>GetOnlyFirstLevelChildren_param</name>
+          <valueProcess>%aditoprj%/entity/Attribute_entity/entityfields/attributechildren/children/getonlyfirstlevelchildren_param/valueProcess.js</valueProcess>
+          <expose v="false" />
+        </entityParameter>
+      </children>
+    </entityProvider>
+    <entityConsumer>
+      <name>ChildAttributes</name>
+      <refreshParent v="true" />
+      <stateProcess>%aditoprj%/entity/Attribute_entity/entityfields/childattributes/stateProcess.js</stateProcess>
+      <dependency>
+        <name>dependency</name>
+        <entityName>Attribute_entity</entityName>
+        <fieldName>AttributeChildren</fieldName>
+      </dependency>
+      <children>
+        <entityParameter>
+          <name>DisplaySimpleName_param</name>
+          <valueProcess>%aditoprj%/entity/Attribute_entity/entityfields/childattributes/children/displaysimplename_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>ParentId_param</name>
+          <valueProcess>%aditoprj%/entity/Attribute_entity/entityfields/childattributes/children/parentid_param/valueProcess.js</valueProcess>
+        </entityParameter>
+        <entityParameter>
+          <name>ParentType_param</name>
+          <valueProcess>%aditoprj%/entity/Attribute_entity/entityfields/childattributes/children/parenttype_param/valueProcess.js</valueProcess>
+        </entityParameter>
+      </children>
+    </entityConsumer>
+    <entityParameter>
+      <name>GetOnlyFirstLevelChildren_param</name>
       <expose v="true" />
-      <description>parent id that is used to preset the parent when the action newChildAttribute is used</description>
     </entityParameter>
     <entityParameter>
-      <name>IncludeParentRecord_param</name>
+      <name>ParentType_param</name>
       <expose v="true" />
-      <documentation>%aditoprj%/entity/Attribute_entity/entityfields/includeparentrecord_param/documentation.adoc</documentation>
     </entityParameter>
   </entityFields>
   <recordContainers>
diff --git a/entity/Attribute_entity/entityfields/attribute_parent_id/valueProcess.js b/entity/Attribute_entity/entityfields/attribute_parent_id/valueProcess.js
index 75b9d2d76b..33e1114869 100644
--- a/entity/Attribute_entity/entityfields/attribute_parent_id/valueProcess.js
+++ b/entity/Attribute_entity/entityfields/attribute_parent_id/valueProcess.js
@@ -2,5 +2,5 @@ import("system.neon");
 import("system.result");
 import("system.vars");
 
-if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$param.ParentIdPreset_param") && vars.get("$this.value") == null)
-    result.string(vars.get("$param.ParentIdPreset_param"));
\ No newline at end of file
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$param.ParentId_param") && vars.get("$this.value") == null)
+    result.string(vars.get("$param.ParentId_param"));
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js b/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js
index 930a7e565b..dc1197f692 100644
--- a/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js
+++ b/entity/Attribute_entity/entityfields/attribute_type/stateProcess.js
@@ -11,7 +11,6 @@ var state = neon.COMPONENTSTATE_EDITABLE;
 if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
 {
     var type = vars.get("$field.ATTRIBUTE_TYPE");
-    var parentType = AttributeUtil.getAttributeType(vars.get("$field.ATTRIBUTE_PARENT_ID"));
     if (AttributeTypeUtil.isGroupType(type))
     {
         var hasSubordinate = newSelect("count(*)")
@@ -24,4 +23,4 @@ if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT || vars.get("$sys.r
     else if (AttributeUtil.hasRelations(vars.get("$field.UID")))
         state = neon.COMPONENTSTATE_READONLY;
 }
-result.string(state)
\ No newline at end of file
+result.string(state);
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/attribute_type/valueProcess.js b/entity/Attribute_entity/entityfields/attribute_type/valueProcess.js
index 20745951e9..c33f753be3 100644
--- a/entity/Attribute_entity/entityfields/attribute_type/valueProcess.js
+++ b/entity/Attribute_entity/entityfields/attribute_type/valueProcess.js
@@ -4,9 +4,9 @@ import("system.result");
 import("system.vars");
 import("Attribute_lib");
 
-if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && vars.get("$field.ATTRIBUTE_PARENT_ID"))
+if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW && (vars.get("$param.ParentType_param") || vars.get("$field.ATTRIBUTE_PARENT_ID")))
 {
-    var parentType = AttributeUtil.getAttributeType(vars.get("$field.ATTRIBUTE_PARENT_ID"));
+    var parentType = vars.get("$param.ParentType_param") || AttributeUtil.getAttributeType(vars.get("$field.ATTRIBUTE_PARENT_ID"));
     var type = vars.get("$this.value");
     var possibleTypes = AttributeTypeUtil.getPossibleChildren(parentType);
     
diff --git a/entity/Attribute_entity/entityfields/attributeactions/children/newchildattribute/onActionProcess.js b/entity/Attribute_entity/entityfields/attributeactions/children/newchildattribute/onActionProcess.js
index f78e4a1844..20effae6f9 100644
--- a/entity/Attribute_entity/entityfields/attributeactions/children/newchildattribute/onActionProcess.js
+++ b/entity/Attribute_entity/entityfields/attributeactions/children/newchildattribute/onActionProcess.js
@@ -8,8 +8,8 @@ if (vars.exists("$local.rows"))
     var row = vars.get("$local.rows");
     var type = row[0].ATTRIBUTE_TYPE.trim();
     if (AttributeTypeUtil.isGroupType(type))
-        params["ParentIdPreset_param"] = row[0].UID;
+        params["ParentId_param"] = row[0].UID;
     else if (row[0].ATTRIBUTE_PARENT_ID)
-        params["ParentIdPreset_param"] = row[0].ATTRIBUTE_PARENT_ID;
+        params["ParentId_param"] = row[0].ATTRIBUTE_PARENT_ID;
 }
 neon.openContext("Attribute", null, null, neon.OPERATINGSTATE_NEW, params);
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/attributechildren/children/getonlyfirstlevelchildren_param/valueProcess.js b/entity/Attribute_entity/entityfields/attributechildren/children/getonlyfirstlevelchildren_param/valueProcess.js
new file mode 100644
index 0000000000..40effa0178
--- /dev/null
+++ b/entity/Attribute_entity/entityfields/attributechildren/children/getonlyfirstlevelchildren_param/valueProcess.js
@@ -0,0 +1,3 @@
+import("system.result");
+
+result.string(true);
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/childattributes/children/displaysimplename_param/valueProcess.js b/entity/Attribute_entity/entityfields/childattributes/children/displaysimplename_param/valueProcess.js
new file mode 100644
index 0000000000..40effa0178
--- /dev/null
+++ b/entity/Attribute_entity/entityfields/childattributes/children/displaysimplename_param/valueProcess.js
@@ -0,0 +1,3 @@
+import("system.result");
+
+result.string(true);
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/childattributes/children/parentid_param/valueProcess.js b/entity/Attribute_entity/entityfields/childattributes/children/parentid_param/valueProcess.js
new file mode 100644
index 0000000000..16c85500b5
--- /dev/null
+++ b/entity/Attribute_entity/entityfields/childattributes/children/parentid_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.vars");
+import("system.result");
+
+result.string(vars.get("$field.UID"));
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/childattributes/children/parenttype_param/valueProcess.js b/entity/Attribute_entity/entityfields/childattributes/children/parenttype_param/valueProcess.js
new file mode 100644
index 0000000000..f3f6d65905
--- /dev/null
+++ b/entity/Attribute_entity/entityfields/childattributes/children/parenttype_param/valueProcess.js
@@ -0,0 +1,4 @@
+import("system.result");
+import("system.vars");
+
+result.string(vars.get("$field.ATTRIBUTE_TYPE"));
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/childattributes/stateProcess.js b/entity/Attribute_entity/entityfields/childattributes/stateProcess.js
new file mode 100644
index 0000000000..cf9174819c
--- /dev/null
+++ b/entity/Attribute_entity/entityfields/childattributes/stateProcess.js
@@ -0,0 +1,6 @@
+import("system.result");
+import("system.neon");
+import("system.vars");
+import("Attribute_lib");
+
+result.string(AttributeTypeUtil.isGroupType(vars.get("$field.ATTRIBUTE_TYPE")) ? neon.COMPONENTSTATE_EDITABLE : neon.COMPONENTSTATE_INVISIBLE);
\ No newline at end of file
diff --git a/entity/Attribute_entity/entityfields/keywordattributetypes/children/whitelistids_param/valueProcess.js b/entity/Attribute_entity/entityfields/keywordattributetypes/children/whitelistids_param/valueProcess.js
index e6e7f7340b..847edb2907 100644
--- a/entity/Attribute_entity/entityfields/keywordattributetypes/children/whitelistids_param/valueProcess.js
+++ b/entity/Attribute_entity/entityfields/keywordattributetypes/children/whitelistids_param/valueProcess.js
@@ -7,7 +7,9 @@ import("Attribute_lib");
 if (vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW || vars.get("$sys.recordstate") == neon.OPERATINGSTATE_EDIT)
 {
     var type;
-    if (vars.get("$field.ATTRIBUTE_PARENT_ID"))
+    if (vars.get("$param.ParentType_param"))
+        type = vars.get("$param.ParentType_param");
+    else if (vars.get("$field.ATTRIBUTE_PARENT_ID"))
         type = AttributeUtil.getAttributeType(vars.get("$field.ATTRIBUTE_PARENT_ID"));
     else
         type = $AttributeTypes.GROUP.toString(); //GROUP can have everything except COMBOVALUE as child
diff --git a/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js b/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js
index 9d50cc58b4..c5b4ef81cd 100644
--- a/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js
+++ b/entity/Attribute_entity/recordcontainers/jdito/contentProcess.js
@@ -14,98 +14,90 @@ var childId = vars.get("$param.ChildId_param");
 var childType = vars.get("$param.ChildType_param");
 
 var objectType = vars.get("$param.ObjectType_param");
-var filteredIds = vars.getString("$param.FilteredAttributeIds_param") ? JSON.parse(vars.getString("$param.FilteredAttributeIds_param")) : null
+var filteredIds = vars.get("$param.FilteredAttributeIds_param") ? JSON.parse(vars.getString("$param.FilteredAttributeIds_param")) : null
 var attributeCountObj = vars.get("$param.AttributeCount_param") ? JSON.parse(vars.getString("$param.AttributeCount_param")) : null;
-var displaySimpleName = vars.getString("$param.DisplaySimpleName_param") == "true" ? true : false;
+var displaySimpleName = Utils.toBoolean(vars.get("$param.DisplaySimpleName_param"));
 
 var themeObjectRowId = vars.get("$param.ThemeObjectRowId_param");
 
 var parentId = vars.get("$param.ParentId_param");
-var includeParentRecord = vars.get("$param.IncludeParentRecord_param");
+var includeParentRecord = Utils.toBoolean(vars.get("$param.IncludeParentRecord_param"));
+var onlyFirstLevelChildren = Utils.toBoolean(vars.get("$param.GetOnlyFirstLevelChildren_param"));
 
 var fetchUsages = false;
 var translateName = false;
 
 var condition = newWhere();
 
-var emptyResult = function ()
+if (vars.exists("$local.idvalues") && vars.get("$local.idvalues"))
 {
-    if (vars.exists("$local.idvalues") && vars.get("$local.idvalues"))
-    {
-        condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", vars.get("$local.idvalues"), SqlBuilder.IN()); 
-        fetchUsages = true;
-        return false;
-    }
-    
-    if (childId) //if a childId is given, it is the lookup for selecting the superordinate attribute
-    {
-        condition.and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", AttributeTypeUtil.getGroupTypes(childType), SqlBuilder.IN());
-        
-        //filter out the child and all children of the child, because an attribute can't have itself or a subordinate attribute as parent
-        condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", [childId].concat(AttributeUtil.getAllChildren(childId)), SqlBuilder.NOT_IN());
-    }
-    else if (objectType)  //if there's an objectType, it comes from the AttributeRelation entity (lookup for the attribute selection)
-    {
-        translateName = true;
-        
-        var ids = AttributeUtil.getPossibleAttributes(objectType, true, filteredIds, attributeCountObj);
-        
-        if (ids.length === 0)
-            return true;
-        
-        condition.and("AB_ATTRIBUTE.AB_ATTRIBUTEID", ids, SqlBuilder.IN());
-        
-        condition.and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.THEME, !themeObjectRowId ? SqlBuilder.NOT_EQUAL() : undefined);
-    }
-    else if (parentId)
+    condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", vars.get("$local.idvalues"), SqlBuilder.IN()); 
+    fetchUsages = true;
+}
+else if (childId) //if a childId is given, it is the lookup for selecting the superordinate attribute
+{
+    condition.and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", AttributeTypeUtil.getGroupTypes(childType), SqlBuilder.IN());
+
+    //filter out the child and all children of the child, because an attribute can't have itself or a subordinate attribute as parent
+    condition.andIfSet("AB_ATTRIBUTE.AB_ATTRIBUTEID", [childId].concat(AttributeUtil.getAllChildren(childId)), SqlBuilder.NOT_IN());
+}
+else if (objectType)  //if there's an objectType, it comes from the AttributeRelation entity (lookup for the attribute selection)
+{
+    translateName = true;
+
+    var ids = AttributeUtil.getPossibleAttributes(objectType, true, filteredIds, attributeCountObj);
+
+    if (Utils.isEmpty(ids))
+        condition.noResult();
+
+    condition.and("AB_ATTRIBUTE.AB_ATTRIBUTEID", ids, SqlBuilder.IN());
+    condition.and("AB_ATTRIBUTE.ATTRIBUTE_TYPE", $AttributeTypes.THEME, !themeObjectRowId ? SqlBuilder.NOT_EQUAL() : undefined);
+}
+else if (parentId)
+{
+    if (onlyFirstLevelChildren)
+        condition.and("AB_ATTRIBUTE.ATTRIBUTE_PARENT_ID", parentId);
+    else
     {
         condition.and("AB_ATTRIBUTE.AB_ATTRIBUTEID", AttributeUtil.getAllChildren(parentId), SqlBuilder.IN());
         translateName = true;
-        if(includeParentRecord == "true")
+        if(includeParentRecord)
             condition.or("AB_ATTRIBUTE.AB_ATTRIBUTEID", parentId);
     }
-    else
-    {
-        fetchUsages = true;
-    }
+}
+else
+{
+    fetchUsages = true;
+}
 
-    //when there are filters selected, add them to the conditon
-    if (vars.exists("$local.filter") && vars.get("$local.filter"))
-    {
-        var filter = vars.get("$local.filter");
-        if (filter.filter)
-            condition.andIfSet(JditoFilterUtils.getSqlCondition(filter.filter, "AB_ATTRIBUTE", undefined, {
-                // special filter for usage
-                USAGE_FILTER : function (pValue, pOperator)
-                {
-                    var cond = newWhere();
-                    var subSelect = newSelect("1").from("AB_ATTRIBUTEUSAGE", "attrUse").where("attrUse.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID");
-
-                    switch (pOperator)
-                    {
-                        case "EQUAL":
-                        case "NOT_EQUAL":
-                            subSelect.and(["AB_ATTRIBUTEUSAGE", "AB_ATTRIBUTE_ID", "attrUse"], pValue);
-                        case "ISNULL":
-                        case "ISNOTNULL":
-                            return cond.and(null, subSelect, pOperator == "NOT_EQUAL" || pOperator == "ISNULL" ? SqlBuilder.NOT_EXISTS() : SqlBuilder.EXISTS());
-                    }
-                    return cond;
-                }
-            }));
-    }
-    
-    return false;
-}();
+var filterCondition = new FilterSqlTranslator(vars.get("$local.filter"), "AB_ATTRIBUTE")    
+    .addSpecialFieldConditionFn("USAGE_FILTER", function (pValue, pOperator)
+        {
+            var cond = newWhere();
+            var subSelect = newSelect("1").from("AB_ATTRIBUTEUSAGE", "attrUse").where("attrUse.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID");
+
+            switch (pOperator)
+            {
+                case "EQUAL":
+                case "NOT_EQUAL":
+                    subSelect.and(["AB_ATTRIBUTEUSAGE", "AB_ATTRIBUTE_ID", "attrUse"], pValue);
+                case "ISNULL":
+                case "ISNOTNULL":
+                    return cond.and(null, subSelect, pOperator == "NOT_EQUAL" || pOperator == "ISNULL" ? SqlBuilder.NOT_EXISTS() : SqlBuilder.EXISTS());
+            }
+            return cond;
+        })
+    .getSqlCondition();
+condition.andIfSet(filterCondition);
 
 var usages;
 if (fetchUsages) //this query is only necessary in Attribute, not in AttributeRelation
 {                        
     var usageTbl = newSelect("AB_ATTRIBUTE_ID, OBJECT_TYPE")
-             .from("AB_ATTRIBUTEUSAGE")
-             .join("AB_ATTRIBUTE", newWhere("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID"))
-             .whereIfSet(condition)
-             .table();
+        .from("AB_ATTRIBUTEUSAGE")
+        .join("AB_ATTRIBUTE", "AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID = AB_ATTRIBUTE.AB_ATTRIBUTEID")
+        .whereIfSet(condition)
+        .table();
     usages = {};
     for (let i = 0, l = usageTbl.length; i < l; i++)
     {
@@ -117,16 +109,18 @@ if (fetchUsages) //this query is only necessary in Attribute, not in AttributeRe
     }
 }
 
-var attributes = newSelect("AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME, ATTRIBUTE_ACTIVE, DROPDOWNDEFINITION, DROPDOWNFILTER, SORTING, ATTRIBUTE_TYPE, " 
-                            + KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.attributeType(), "ATTRIBUTE_TYPE") //3
-                            + ", '', '', ''")
+var attributes = newSelect(["AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME, ATTRIBUTE_ACTIVE, DROPDOWNDEFINITION, DROPDOWNFILTER, SORTING, ATTRIBUTE_TYPE",
+                            KeywordUtils.getResolvedTitleSqlPart($KeywordRegistry.attributeType(), "ATTRIBUTE_TYPE"), //3
+                            "'', '', ''"])
                     .from("AB_ATTRIBUTE")
                     .whereIfSet(condition)
-                    .orderBy("ATTRIBUTE_PARENT_ID asc, SORTING asc")
-                    .table(emptyResult);
+                    .orderBy("ATTRIBUTE_PARENT_ID, SORTING, ATTRIBUTE_NAME")
+                    .table();
 
-//TODO: attribute name caching like keywords
-var allNames = !emptyResult ? newSelect("AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME").from("AB_ATTRIBUTE").table() : [];
+var allNames = newSelect("AB_ATTRIBUTEID, ATTRIBUTE_PARENT_ID, ATTRIBUTE_NAME")
+    .from("AB_ATTRIBUTE")
+    .table(Utils.isEmpty(attributes));
+    
 var attrNameData = {};
 for (let i = 0, l = allNames.length; i < l; i++)
 {
diff --git a/entity/Attribute_entity/recordcontainers/jdito/onInsert.js b/entity/Attribute_entity/recordcontainers/jdito/onInsert.js
index 45e6ba816f..7e2f545778 100644
--- a/entity/Attribute_entity/recordcontainers/jdito/onInsert.js
+++ b/entity/Attribute_entity/recordcontainers/jdito/onInsert.js
@@ -1,5 +1,6 @@
 import("system.vars");
 import("Sql_lib");
+import("Attribute_lib");
 
 var rowdata = vars.get("$local.rowdata");
 
@@ -12,4 +13,22 @@ new SqlBuilder().insertFields({
     "ATTRIBUTE_TYPE" : rowdata["ATTRIBUTE_TYPE.value"],
     "DROPDOWNFILTER" : rowdata["DROPDOWNFILTER.value"],
     "SORTING" : rowdata["SORTING.value"]
-}, "AB_ATTRIBUTE");
\ No newline at end of file
+}, "AB_ATTRIBUTE");
+
+if (rowdata["ATTRIBUTE_PARENT_ID.value"] && rowdata["ATTRIBUTE_TYPE.value"] !== $AttributeTypes.COMBOVALUE.toString() && vars.get("$param.GetOnlyFirstLevelChildren_param"))
+{
+    var parentUsages = newSelect("OBJECT_TYPE")
+        .from("AB_ATTRIBUTEUSAGE")
+        .where("AB_ATTRIBUTEUSAGE.AB_ATTRIBUTE_ID", rowdata["ATTRIBUTE_PARENT_ID.value"])
+        .arrayColumn();
+        
+    var usageValues = {};
+    if (AttributeTypeUtil.isSingleSelection(rowdata["ATTRIBUTE_TYPE.value"]))
+        usageValues["MAX_COUNT"] = 1;
+    
+    parentUsages.forEach(function (usageContext)
+    {
+        usageValues["OBJECT_TYPE"] = usageContext;
+        new SqlBuilder().insertFields(usageValues, "AB_ATTRIBUTEUSAGE", "AB_ATTRIBUTEUSAGEID");
+    });
+}
\ No newline at end of file
diff --git a/entity/Person_entity/entityfields/date_new/valueProcess.js b/entity/Person_entity/entityfields/date_new/valueProcess.js
index a72892783b..9cf1e32dd7 100644
--- a/entity/Person_entity/entityfields/date_new/valueProcess.js
+++ b/entity/Person_entity/entityfields/date_new/valueProcess.js
@@ -1,7 +1,12 @@
+import("Entity_lib");
 import("system.util");
 import("system.result");
 import("system.neon");
 import("system.vars");
 
 if(vars.get("$sys.recordstate") == neon.OPERATINGSTATE_NEW)
-    result.string(vars.get("$sys.date"));
\ No newline at end of file
+    result.string(vars.get("$sys.date"));
+    
+    "$field.Attributes.deletedRows";
+    
+    EntityConsumerRowsHelper.getCurrentConsumerRows("Attributes", ["VALUE"])
\ No newline at end of file
diff --git a/neonContext/Attribute/Attribute.aod b/neonContext/Attribute/Attribute.aod
index cc3899d5c0..749cae00fe 100644
--- a/neonContext/Attribute/Attribute.aod
+++ b/neonContext/Attribute/Attribute.aod
@@ -30,5 +30,13 @@
       <name>a380915a-6946-4923-9b13-7a981606ce60</name>
       <view>AttributeLookup_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>db1f22e8-46f8-40aa-a5eb-00c606666c96</name>
+      <view>AttributeMultiEdit_view</view>
+    </neonViewReference>
+    <neonViewReference>
+      <name>1cf7d11d-d593-4518-b7aa-aca1a9a2fb8a</name>
+      <view>AttributeList_view</view>
+    </neonViewReference>
   </references>
 </neonContext>
diff --git a/neonView/AttributeEdit_view/AttributeEdit_view.aod b/neonView/AttributeEdit_view/AttributeEdit_view.aod
index 5668d586c0..f9a869de8f 100644
--- a/neonView/AttributeEdit_view/AttributeEdit_view.aod
+++ b/neonView/AttributeEdit_view/AttributeEdit_view.aod
@@ -50,5 +50,10 @@
       <entityField>AttributeUsages</entityField>
       <view>AttributeUsageMultiEdit_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>90d4edc1-699d-413f-bbcd-d14a90cd8cf9</name>
+      <entityField>ChildAttributes</entityField>
+      <view>AttributeMultiEdit_view</view>
+    </neonViewReference>
   </children>
 </neonView>
diff --git a/neonView/AttributeList_view/AttributeList_view.aod b/neonView/AttributeList_view/AttributeList_view.aod
new file mode 100644
index 0000000000..774de73db9
--- /dev/null
+++ b/neonView/AttributeList_view/AttributeList_view.aod
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
+  <name>AttributeList_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <titledListViewTemplate>
+      <name>AttributeList</name>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonTitledListTableColumn>
+          <name>96544713-a302-4e2f-ab7f-6c02d44d9908</name>
+          <entityField>ATTRIBUTE_NAME</entityField>
+        </neonTitledListTableColumn>
+        <neonTitledListTableColumn>
+          <name>5c536673-78f5-482c-aa98-f027f08659e1</name>
+          <entityField>ATTRIBUTE_TYPE</entityField>
+        </neonTitledListTableColumn>
+        <neonTitledListTableColumn>
+          <name>fcd31169-8b19-4165-bb85-200ab6045cdd</name>
+          <entityField>DROPDOWNDEFINITION</entityField>
+        </neonTitledListTableColumn>
+      </columns>
+    </titledListViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/AttributeMultiEdit_view/AttributeMultiEdit_view.aod b/neonView/AttributeMultiEdit_view/AttributeMultiEdit_view.aod
new file mode 100644
index 0000000000..21e86a1d4d
--- /dev/null
+++ b/neonView/AttributeMultiEdit_view/AttributeMultiEdit_view.aod
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<neonView xmlns="http://www.adito.de/2018/ao/Model" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" VERSION="1.1.6" xsi:schemaLocation="http://www.adito.de/2018/ao/Model adito://models/xsd/neonView/1.1.6">
+  <name>AttributeMultiEdit_view</name>
+  <majorModelMode>DISTRIBUTED</majorModelMode>
+  <layout>
+    <noneLayout>
+      <name>layout</name>
+    </noneLayout>
+  </layout>
+  <children>
+    <genericMultipleViewTemplate>
+      <name>GenericMultiple</name>
+      <entityField>#ENTITY</entityField>
+      <columns>
+        <neonGenericMultipleTableColumn>
+          <name>59d4b058-675b-4124-a510-a576e2222815</name>
+          <entityField>ATTRIBUTE_NAME</entityField>
+        </neonGenericMultipleTableColumn>
+        <neonGenericMultipleTableColumn>
+          <name>e6660015-3e4a-47d3-aee5-0458e8e8b8e3</name>
+          <entityField>ATTRIBUTE_TYPE</entityField>
+        </neonGenericMultipleTableColumn>
+        <neonGenericMultipleTableColumn>
+          <name>67d03576-b62e-42ab-a17e-220b2468a315</name>
+          <entityField>DROPDOWNDEFINITION</entityField>
+        </neonGenericMultipleTableColumn>
+      </columns>
+    </genericMultipleViewTemplate>
+  </children>
+</neonView>
diff --git a/neonView/AttributePreview_view/AttributePreview_view.aod b/neonView/AttributePreview_view/AttributePreview_view.aod
index bdcc189835..88b71eba21 100644
--- a/neonView/AttributePreview_view/AttributePreview_view.aod
+++ b/neonView/AttributePreview_view/AttributePreview_view.aod
@@ -45,5 +45,10 @@
       <entityField>AttributeUsages</entityField>
       <view>AttributeUsageList_view</view>
     </neonViewReference>
+    <neonViewReference>
+      <name>87719160-f477-49c7-b8de-5386d4c03a45</name>
+      <entityField>ChildAttributes</entityField>
+      <view>AttributeList_view</view>
+    </neonViewReference>
   </children>
 </neonView>
-- 
GitLab