diff --git a/devdocs/specs/core-main-grids.txt b/devdocs/specs/core-main-grids.txt index 389e1b4e..b23afe6d 100644 --- a/devdocs/specs/core-main-grids.txt +++ b/devdocs/specs/core-main-grids.txt @@ -31,10 +31,11 @@ Client - Each row contains a bunch of row objects - Each column from the db is converted to an object and is formatted like this: - {v:[field value],id:42[optional id value if openable]}, {v:[field value],id:42[optional id value if openable]}...etc - - df First column object is ALWAYS the Default "df" object and is not intended for display - - First column contains the same format as a normal column but doesn't display and is intended for the client to know what type and ID of object to open - - This is necessary in cases where they have made selections that preclude knowing what link to open, so if there is no links in the row this is the default for the entire row - - This also saves bandwidth as a list that has no other types can not bother setting the type or id for any other columns + - rid flag: (was df) + - A column with a flag of rid:true means it's the RowId column or IsRowId and must be visible to user at client + - rid is not required because some datalists won't need one to open a record or have a practical row id due to the nature of the data + - for example ones used for REPORTING + - COLUMNS the list comes back as an object with not only the actual columns but also a separate property listing the set of columns in order to be displayed - Also their data type @@ -52,10 +53,8 @@ Server - SERVER SENDS LIST OF COLUMNS - The server needs to tell the client which columns are coming back with the list and what types etc so the client can just adapt to any template setting - column list has type of object behind each column if applicable and user has rights to open so client can make hyperlinks - - FIRST column in column list is always the DEFAULT column corresponding to the first "default" column in the data row - - cm value is always "df" - - dt value is always 0 (dt:0) - - AyaType is always the default type to open, if it's nothing there is nothing to open (not likely) + - RID flagged column in column list is always the default RowID column corresponding to the underlying object and ID in the datalist + - rid column must have an id and an object type to be valid rid column - SERVER SENDS DATA - Data in a standard format all grid lists json format, not based on set objects (I think I can do that, probably a hybrid object with JSON data) - Each row has each column as a object comprising of: @@ -64,7 +63,7 @@ Server - To save bandwidth abbreviations are used in the column definitions: - ColumnsJSON=@"""columns"":[ {""cm"":""Widget"",""dt"":""text"",""ay"":"+ AyaType.Widget.ToString()+ "}]"; - cm=column name locale key, dt=AyDataType, ay=AyaType to open on click of that column field (optional, not present if not openable) - - First column in each row is *ALWAYS* the DEFAULT column that corresponds to the df column specified in objectfields with it's sql attributes + - rid flagged column in each row is *ALWAYS* the rowID column specified in objectfields with it's sql attributes - For example (wide list): data:{ columns:{[ {cm:"lt_client_name",dt:text,ay:2},{cm:"lt_client_notes",dt:text},{cm:"lt_last_workorder",dt:number,ay:workorder}]} diff --git a/docs/8.0/ayanova/docs/api-response-format.md b/docs/8.0/ayanova/docs/api-response-format.md index 9af009ba..1dd24422 100644 --- a/docs/8.0/ayanova/docs/api-response-format.md +++ b/docs/8.0/ayanova/docs/api-response-format.md @@ -79,16 +79,12 @@ Response: "next": "http://localhost:7575/api/v8/DataList/List?DataListKey=TestWidgetDataList&pageNo=3&pageSize=2", "last": "http://localhost:7575/api/v8/DataList/List?DataListKey=TestWidgetDataList&pageNo=50&pageSize=2" }, - "columns": [ - { - "cm": "df", - "dt": 0, - "ay": 2 - }, + "columns": [ { "cm": "WidgetName", "dt": 4, - "ay": 2 + "ay": 2, + "rid":1 }, { "cm": "WidgetSerial", @@ -123,7 +119,7 @@ Response: `Previous` or `next` properties will contain "null" instead of an url on boundaries where there is no record to link to. `columns` collection is the list of columns returned in the same order as the individual data arrays for each object. -Note that the `df` column is the default column and contains the object type and id to open for that row which guarantees an openable object for the row regardless of which columns are templated to be returned. +Note that the column with the `rid` flag is the default row ID column and contains the object type and id to open for that row which guarantees an openable object for the row regardless of which columns are set to be returned. ### PUT RESPONSE diff --git a/server/AyaNova/DataList/AyaDataList.cs b/server/AyaNova/DataList/AyaDataList.cs index e55407c3..900edf47 100644 --- a/server/AyaNova/DataList/AyaDataList.cs +++ b/server/AyaNova/DataList/AyaDataList.cs @@ -19,7 +19,7 @@ namespace AyaNova.DataList } public string SQLFrom { get; set; } - public List FieldDefinitions { get; set; }//NOTE: First field after df is used as the title above the narrow grid view so it should be the name of the item to be shown that is most identifiable + public List FieldDefinitions { get; set; } public AuthorizationRoles AllowedRoles { get; set; } public AyaType DefaultListObjectType { get; set; } @@ -50,8 +50,7 @@ namespace AyaNova.DataList StringBuilder sb = new StringBuilder(); sb.Append("["); - //df First column is always the df column - sb.Append($"{{\"cm\":\"df\",\"dt\":0,\"ay\":{(int)DefaultListObjectType}}}"); + foreach (string s in ListViewFieldKeys) { @@ -75,6 +74,11 @@ namespace AyaNova.DataList //Has a AyObjectType? (linkable / openable) if (o.AyaObjectType != 0) sb.Append($",\"ay\":{(int)o.AyaObjectType}"); + + //Row ID column? + if(o.IsRowId){ + sb.Append($",\"rid\":1"); + } //Has a Enumtype? if (!string.IsNullOrEmpty(o.EnumType)) diff --git a/server/AyaNova/DataList/AyaDataListFieldDefinition.cs b/server/AyaNova/DataList/AyaDataListFieldDefinition.cs index 0111a222..1277250e 100644 --- a/server/AyaNova/DataList/AyaDataListFieldDefinition.cs +++ b/server/AyaNova/DataList/AyaDataListFieldDefinition.cs @@ -30,6 +30,10 @@ namespace AyaNova.DataList //CLIENT Use only for display public string EnumType { get; set; } + //SERVER / CLIENT - used to identify the column that represents the entire row ID and object + //MUST be present in all datalists and displayed at the client + public bool IsRowId { get; set; } + //CLIENT / SERVER - client display and to indicate what object to open , Server for formatting return object public int AyaObjectType { get; set; } @@ -41,6 +45,9 @@ namespace AyaNova.DataList public string SqlValueColumnName { get; set; } + + + public AyaDataListFieldDefinition() { //most common defaults @@ -48,6 +55,7 @@ namespace AyaNova.DataList IsCustomField = false; IsFilterable = true; IsSortable = true; + IsRowId = false; //Set openable object type to no type which is the default and means it's not a link to another object AyaObjectType = (int)AyaType.NoType; diff --git a/server/AyaNova/DataList/DataListFetcher.cs b/server/AyaNova/DataList/DataListFetcher.cs index f034a2e3..28491807 100644 --- a/server/AyaNova/DataList/DataListFetcher.cs +++ b/server/AyaNova/DataList/DataListFetcher.cs @@ -72,7 +72,7 @@ namespace AyaNova.DataList qTotalRecordsQuery = $"SELECT COUNT(*) {qFrom} {qWhere}".Replace(" ", " "); //RETURN OBJECTS - int returnRowColumnCount = ListViewFieldList.Count();// + 1;//Templates don't have the DF column in them but we need it and it's in the query so plus one + int returnRowColumnCount = ListViewFieldList.Count(); List> rows = new List>(); long totalRecordCount = 0; @@ -89,28 +89,11 @@ namespace AyaNova.DataList { List row = new List(returnRowColumnCount); - //PROCESS THE DF DEFAULT FIRST COLUMN - //first column is always the underlying id value of the default record to open for this row in the client ui - if (!dr.IsDBNull(0)) - { - row.Add(new AyaFieldData() { v = dr.GetInt64(0) }); - } - else - { -#if (DEBUG) - throw new System.ArgumentNullException($"DEV ERROR in DataListFetcher.cs: fetching df column for {DataListKey} df value is null, expecting long int record value"); -#endif - } - - //GetOrdinal by name is flakey in npgsql so just going by field definition and ordinal numerically - // int nCurrentColumnPointer = 1;//start at 1 - // dr.GetOrdinal(); - // dr.GetName(); + //INSERT REMAINING FIELDS FROM TEMPLATE INTO THE RETURN ROWS LIST foreach (string TemplateField in ListViewFieldList) { - if (TemplateField == "df") - continue; + //get the AyaObjectFieldDefinition AyaDataListFieldDefinition f = DataList.FieldDefinitions.FirstOrDefault(x => x.FieldKey == TemplateField); if (f.IsCustomField) @@ -150,15 +133,14 @@ dr.GetOrdinal("customfields"); { AyaFieldData AyaField = new AyaFieldData(); AyaField.v = dr.GetValue(SelectBuild.map[f.GetSqlValueColumnName()]); - //nCurrentColumnPointer++; - if (f.SqlIdColumnName != null)//skip over df column id, it's not there + + if (f.SqlIdColumnName != null) { var ordinal = SelectBuild.map[f.SqlIdColumnName]; if (!await dr.IsDBNullAsync(ordinal)) AyaField.i = dr.GetInt64(ordinal); - //nCurrentColumnPointer++; } row.Add(AyaField); } diff --git a/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs b/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs index d7bd6757..cf068fc5 100644 --- a/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlFilterOrderByBuilder.cs @@ -60,9 +60,10 @@ namespace AyaNova.DataList if (sb.Length == 0) { //no sort specified so default it - if (objectFieldsList[0].FieldKey == "df") + AyaDataListFieldDefinition rid = objectFieldsList.FirstOrDefault(x => x.IsRowId == true); + if (rid!=null) { - return $"ORDER BY {objectFieldsList[0].SqlIdColumnName} DESC"; + return $"ORDER BY {rid.SqlIdColumnName} DESC"; } else { diff --git a/server/AyaNova/DataList/DataListSqlSelectBuilder.cs b/server/AyaNova/DataList/DataListSqlSelectBuilder.cs index 5c56ee4d..4e267a5f 100644 --- a/server/AyaNova/DataList/DataListSqlSelectBuilder.cs +++ b/server/AyaNova/DataList/DataListSqlSelectBuilder.cs @@ -25,22 +25,23 @@ namespace AyaNova.DataList StringBuilder sb = new StringBuilder(); sb.Append("SELECT "); - //Default ID column for each row (always is aliased as df) - AyaDataListFieldDefinition def = objectFieldsList.FirstOrDefault(x => x.FieldKey == "df"); - if (def == null) - { - throw new System.ArgumentNullException("DataListSqlSelectBuilder: objectFieldList is missing the df default field"); - } - if (string.IsNullOrEmpty(def.SqlIdColumnName)) - { - sb.Append("id");//default when no alternate column is specified - } - else - { - sb.Append(def.SqlIdColumnName); - } + //DEPRECATED + // //Default ID column for each row (always is aliased as df) + // AyaDataListFieldDefinition def = objectFieldsList.FirstOrDefault(x => x.FieldKey == "df"); + // if (def == null) + // { + // throw new System.ArgumentNullException("DataListSqlSelectBuilder: objectFieldList is missing the df default field"); + // } + // if (string.IsNullOrEmpty(def.SqlIdColumnName)) + // { + // sb.Append("id");//default when no alternate column is specified + // } + // else + // { + // sb.Append(def.SqlIdColumnName); + // } - sb.Append(" AS df"); + // sb.Append(" AS df"); //keep track of which custom fields columns were added already //this ensures that if there is more than one set of custom fields like from two different objects in the list @@ -49,13 +50,15 @@ namespace AyaNova.DataList //map sql column name to ordinal name Dictionary map = new Dictionary(); - map.Add("df", 0); + //DEPRECATED map.Add("df", 0); int nOrdinal = 0; + + foreach (string ColumnName in listViewFieldList) { - //skip the df column, it's already been processed above - if (ColumnName == "df") - continue; + // //skip the df column, it's already been processed above + // if (ColumnName == "df") + // continue; AyaDataListFieldDefinition o = objectFieldsList.FirstOrDefault(x => x.FieldKey == ColumnName); #if (DEBUG) //Developers little helper @@ -76,7 +79,7 @@ namespace AyaNova.DataList { //nope sb.Append(", "); sb.Append(CustomFieldSqlColumnName); - map.Add(CustomFieldSqlColumnName, ++nOrdinal); + map.Add(CustomFieldSqlColumnName, nOrdinal++); } //if it was already added then can just ignore it // else @@ -106,6 +109,7 @@ namespace AyaNova.DataList map.Add(idColumnName, ++nOrdinal); } } + } } diff --git a/server/AyaNova/DataList/TestUserDataList.cs b/server/AyaNova/DataList/TestUserDataList.cs index ecfc22e7..5bd87ee1 100644 --- a/server/AyaNova/DataList/TestUserDataList.cs +++ b/server/AyaNova/DataList/TestUserDataList.cs @@ -42,7 +42,7 @@ namespace AyaNova.DataList //NOTE: Due to the join, all the sql id and name fields that can conflict with the joined (in this case User) table need to be specified completely FieldDefinitions = new List(); - FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.User, SqlIdColumnName = "auser.id" }); + //DPRECATED FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.User, SqlIdColumnName = "auser.id" }); FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "User", @@ -50,7 +50,8 @@ namespace AyaNova.DataList AyaObjectType = (int)AyaType.User, UiFieldDataType = (int)UiFieldDataType.Text, SqlIdColumnName = "auser.id", - SqlValueColumnName = "auser.name" + SqlValueColumnName = "auser.name", + IsRowId=true }); FieldDefinitions.Add(new AyaDataListFieldDefinition diff --git a/server/AyaNova/DataList/TestWidgetDataList.cs b/server/AyaNova/DataList/TestWidgetDataList.cs index 10b2d07c..c2c12969 100644 --- a/server/AyaNova/DataList/TestWidgetDataList.cs +++ b/server/AyaNova/DataList/TestWidgetDataList.cs @@ -58,8 +58,8 @@ namespace AyaNova.DataList //NOTE: Due to the join, all the sql id and name fields that can conflict with the joined (in this case User) table need to be specified completely FieldDefinitions = new List(); - FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.Widget, SqlIdColumnName = "awidget.id", IsFilterable = false, IsSortable = false, }); - //NOTE: First field after df is used as the title above the narrow grid view so it should be the name of the item to be shown that is most identifiable + //DEPRECATED: FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.Widget, SqlIdColumnName = "awidget.id", IsFilterable = false, IsSortable = false, }); + FieldDefinitions.Add(new AyaDataListFieldDefinition { LtKey = "WidgetName", @@ -67,7 +67,8 @@ namespace AyaNova.DataList AyaObjectType = (int)AyaType.Widget, UiFieldDataType = (int)UiFieldDataType.Text, SqlIdColumnName = "awidget.id", - SqlValueColumnName = "awidget.name" + SqlValueColumnName = "awidget.name", + IsRowId = true }); FieldDefinitions.Add(new AyaDataListFieldDefinition { diff --git a/server/AyaNova/DataList/TestWidgetUserEmailDataList.cs b/server/AyaNova/DataList/TestWidgetUserEmailDataList.cs index 794adfda..3de3c1f0 100644 --- a/server/AyaNova/DataList/TestWidgetUserEmailDataList.cs +++ b/server/AyaNova/DataList/TestWidgetUserEmailDataList.cs @@ -26,7 +26,7 @@ namespace AyaNova.DataList dynamic cm = new JObject(); cm.fld = "widgetname"; dlistView.Add(cm); - + cm = new JObject(); cm.fld = "username"; dlistView.Add(cm); @@ -44,7 +44,7 @@ namespace AyaNova.DataList //NOTE: First field after df is used as the title above the narrow grid view so it should be the name of the item to be shown that is most identifiable FieldDefinitions = new List(); - FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.Widget, SqlIdColumnName = "awidget.id" }); + //DEPRECATED FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "df", AyaObjectType = (int)AyaType.Widget, SqlIdColumnName = "awidget.id" }); FieldDefinitions.Add(new AyaDataListFieldDefinition { FieldKey = "widgetname", @@ -52,7 +52,8 @@ namespace AyaNova.DataList UiFieldDataType = (int)UiFieldDataType.Text, AyaObjectType = (int)AyaType.Widget, SqlIdColumnName = "awidget.id", - SqlValueColumnName = "awidget.name" + SqlValueColumnName = "awidget.name", + IsRowId = true }); FieldDefinitions.Add(new AyaDataListFieldDefinition {