This commit is contained in:
2020-02-13 20:50:53 +00:00
parent 5aacb87a93
commit 684f7be73d
7 changed files with 141 additions and 131 deletions

View File

@@ -27,8 +27,7 @@ Users can select a datalistview for a picklist DataList which will in turn affec
Users will get the default hard coded DataListView built into the DataList that is specified for that picklist unless it's changed to an alternative datalistview Users will get the default hard coded DataListView built into the DataList that is specified for that picklist unless it's changed to an alternative datalistview
There is a default PickList format and a default DataTable format pre-defined and hard coded at the server with each dataList definition object There is a default PickList format and a default DataTable format pre-defined and hard coded at the server with each dataList definition object
If the client isn't using a particular dataListView it MUST send the DataListView json as one of the following: If the client isn't using a particular dataListView it MUST send the ListView json as empty string or omit it entirely.
{default:"PickList"} or {default:"DataTable"}
This will instruct the server to use the pre-defined format instead This will instruct the server to use the pre-defined format instead
JSON DataListView format: JSON DataListView format:
@@ -47,6 +46,10 @@ Example:
DataListView JSON: DataListView JSON:
[{key:"COLUMN UNIQUE KEY ID",sort:"-" or "+",filter:{any:true/false,items:[{FILTER OBJECT SEE BELOW}]} }, {key:"second column unique key"},{...etc...}] [{key:"COLUMN UNIQUE KEY ID",sort:"-" or "+",filter:{any:true/false,items:[{FILTER OBJECT SEE BELOW}]} }, {key:"second column unique key"},{...etc...}]
Sort property definition
ID VS NAME
if it's an name *and* id field
Filter object definition: Filter object definition:
Has an "any" boolean property which if true means make an OR query of the conditions if more than one, if nore present or false it means AND each condition (if more than one) Has an "any" boolean property which if true means make an OR query of the conditions if more than one, if nore present or false it means AND each condition (if more than one)

View File

@@ -63,14 +63,7 @@ namespace AyaNova.Api.Controllers
{ {
listOptions.Offset = 0; listOptions.Offset = 0;
} }
//this is to workaround a quirk in the api explorer with default values
if(listOptions.SortJson=="string"){
listOptions.SortJson=string.Empty;
}
if(listOptions.FilterJson=="string"){
listOptions.FilterJson=string.Empty;
}
if (!ModelState.IsValid) if (!ModelState.IsValid)
return BadRequest(new ApiErrorResponse(ModelState)); return BadRequest(new ApiErrorResponse(ModelState));

View File

@@ -20,107 +20,103 @@ namespace AyaNova.DataList
public string SQLFrom { get; set; } public string SQLFrom { get; set; }
public List<AyaDataListFieldDefinition> 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<AyaDataListFieldDefinition> 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 AuthorizationRoles FullListAllowedRoles { get; set; } public AuthorizationRoles AllowedRoles { get; set; }
public AuthorizationRoles MiniListAllowedRoles { get; set; }
public AyaType DefaultListObjectType { get; set; } public AyaType DefaultListObjectType { get; set; }
public string ListKey { get; set; }
public string DefaultDataListDisplayTemplate { get; set; }
public Newtonsoft.Json.Linq.JArray GenerateMINIListColumnsJSON() public string DefaultListView { get; set; }
public Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromListView(string listView)
{ {
//return $"[ {{\"cm\":\"df\",\"dt\":0,\"ay\":{(int)DefaultListObjectType}}},{{\"cm\":\"Widget\",\"dt\":{(int)AyaUiFieldDataType.Text},\"ay\":{(int)DefaultListObjectType}}}]"; throw new System.NotImplementedException("AyaDataList:GenerateListColumnsJSONFromListView not coded yet ");
return JArray.Parse($"[ {{\"cm\":\"df\",\"dt\":0,\"ay\":{(int)DefaultListObjectType}}},{{\"cm\":\"Widget\",\"dt\":{(int)UiFieldDataType.Text},\"ay\":{(int)DefaultListObjectType}}}]"); // //parse the template
} // var jtemplate = JObject.Parse(listView);
public Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromTemplate(string template)
{
//parse the template
var jtemplate = JObject.Parse(template);
//convert to strings (https://stackoverflow.com/a/33836599/8939) // //convert to strings (https://stackoverflow.com/a/33836599/8939)
var fullFields = ((JArray)jtemplate["full"]).ToObject<string[]>(); // var fullFields = ((JArray)jtemplate["full"]).ToObject<string[]>();
//Generate JSON fragment to return with column definitions // //Generate JSON fragment to return with column definitions
StringBuilder sb = new StringBuilder(); // StringBuilder sb = new StringBuilder();
sb.Append("["); // sb.Append("[");
//df First column is always the df column // //df First column is always the df column
sb.Append($"{{\"cm\":\"df\",\"dt\":0,\"ay\":{(int)DefaultListObjectType}}}"); // sb.Append($"{{\"cm\":\"df\",\"dt\":0,\"ay\":{(int)DefaultListObjectType}}}");
foreach (string s in fullFields) // foreach (string s in fullFields)
{ // {
AyaDataListFieldDefinition o = FieldDefinitions.FirstOrDefault(x => x.FieldKey == s); // AyaDataListFieldDefinition o = FieldDefinitions.FirstOrDefault(x => x.FieldKey == s);
#if (DEBUG) // #if (DEBUG)
//Developers little helper // //Developers little helper
if (o == null) // if (o == null)
{ // {
throw new System.ArgumentNullException($"DEV ERROR in AyaDataList::GenerateListColumnsJSONFromTemplate - field {s} specified in template was NOT found in ObjectFields list"); // throw new System.ArgumentNullException($"DEV ERROR in AyaDataList::GenerateListColumnsJSONFromTemplate - field {s} specified in template was NOT found in ObjectFields list");
} // }
#endif // #endif
if (o != null) // if (o != null)
{//Here is where we can vet the field name, if it doesn't exist. For production we'll just ignore those ones // {//Here is where we can vet the field name, if it doesn't exist. For production we'll just ignore those ones
sb.Append(","); // sb.Append(",");
sb.Append("{"); // sb.Append("{");
//Build required part of column definition // //Build required part of column definition
sb.Append($"\"cm\":\"{o.LtKey}\",\"dt\":{(int)o.UiFieldDataType}"); // sb.Append($"\"cm\":\"{o.LtKey}\",\"dt\":{(int)o.UiFieldDataType}");
//Has a AyObjectType? (linkable / openable) // //Has a AyObjectType? (linkable / openable)
if (o.AyaObjectType != 0) // if (o.AyaObjectType != 0)
sb.Append($",\"ay\":{(int)o.AyaObjectType}"); // sb.Append($",\"ay\":{(int)o.AyaObjectType}");
//Has a Enumtype? // //Has a Enumtype?
if (!string.IsNullOrEmpty(o.EnumType)) // if (!string.IsNullOrEmpty(o.EnumType))
sb.Append($",\"et\":\"{AyaNova.Util.StringUtil.TrimTypeName(o.EnumType)}\""); // sb.Append($",\"et\":\"{AyaNova.Util.StringUtil.TrimTypeName(o.EnumType)}\"");
sb.Append("}"); // sb.Append("}");
} // }
} // }
sb.Append("]"); // sb.Append("]");
return JArray.Parse(sb.ToString()); // return JArray.Parse(sb.ToString());
} }
//make sure the template parses and all the fields specified are really existant // //make sure the template parses and all the fields specified are really existant
//this is more for dev errors or api users becuase the client shouldn't generate bad templates // //this is more for dev errors or api users becuase the client shouldn't generate bad templates
public bool ValidateTemplate(string template) // public bool ValidateTemplate(string template)
{ // {
try // try
{ // {
//parse the template // //parse the template
var jtemplate = JObject.Parse(template); // var jtemplate = JObject.Parse(template);
var fullFields = ((JArray)jtemplate["full"]).ToObject<string[]>(); // var fullFields = ((JArray)jtemplate["full"]).ToObject<string[]>();
var miniFields = ((JArray)jtemplate["mini"]).ToObject<string[]>(); // var miniFields = ((JArray)jtemplate["mini"]).ToObject<string[]>();
foreach (string s in fullFields) // foreach (string s in fullFields)
{ // {
AyaDataListFieldDefinition o = FieldDefinitions.FirstOrDefault(x => x.FieldKey == s); // AyaDataListFieldDefinition o = FieldDefinitions.FirstOrDefault(x => x.FieldKey == s);
if (o == null) // if (o == null)
{ // {
return false; // return false;
} // }
} // }
foreach (string s in miniFields) // foreach (string s in miniFields)
{ // {
AyaDataListFieldDefinition o = FieldDefinitions.FirstOrDefault(x => x.FieldKey == s); // AyaDataListFieldDefinition o = FieldDefinitions.FirstOrDefault(x => x.FieldKey == s);
if (o == null) // if (o == null)
{ // {
return false; // return false;
} // }
} // }
} // }
catch // catch
{ // {
return false; // return false;
} // }
return true; // return true;
} // }
}//eoc }//eoc

View File

@@ -185,7 +185,7 @@ namespace AyaNova.DataList
} }
else else
{ {
ColumnsJSON = DataList.GenerateListColumnsJSONFromTemplate(JSONDataListTemplate); ColumnsJSON = DataList.GenerateListColumnsJSONFromListView(JSONDataListTemplate);
} }

View File

@@ -4,34 +4,25 @@ namespace AyaNova.DataList
{ {
internal interface IAyaDataList internal interface IAyaDataList
{ {
//Unique key to identify this list
string ListKey { get; set; }
//sql query from fragment with table joins et //sql query from fragment with table joins et
string SQLFrom { get; set; } string SQLFrom { get; set; }
//List of fields for this object //List of fields for this object
List<AyaDataListFieldDefinition> 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 List<AyaDataListFieldDefinition> FieldDefinitions { get; set; }
//allowed roles to access the full list templated fields
AuthorizationRoles FullListAllowedRoles { get; set; }
//allowed roles to access mini list templated fields
//generally this will be *any* because most forms will need to allow this for picklists such as usernames etc
// but this is a safety valve for sensitive lists like financial reports where there is just no need for untrusted roles to see it
AuthorizationRoles MiniListAllowedRoles { get; set; }
//allowed roles to access this list
AuthorizationRoles AllowedRoles { get; set; }
//Default object type to open for rows of this list (use no object if no) //Default object type to open for rows of this list (use no object if no)
AyaType DefaultListObjectType { get; set; } AyaType DefaultListObjectType { get; set; }
//Default list display template if none found in db or is invalid, this ensures the data will flow even if people fuck up the templates somehow //Default / STOCK DataListView when none is specified
string DefaultDataListDisplayTemplate { get; set; } string DefaultListView { get; set; }
Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromListView(string template);
Newtonsoft.Json.Linq.JArray GenerateMINIListColumnsJSON(); // bool ValidateTemplate(string template);
Newtonsoft.Json.Linq.JArray GenerateListColumnsJSONFromTemplate(string template);
bool ValidateTemplate(string template);
} }

View File

@@ -1,7 +1,7 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace AyaNova.Api.ControllerHelpers namespace AyaNova.DataList
{ {
public sealed class ListOptions public sealed class ListOptions
@@ -15,23 +15,15 @@ namespace AyaNova.Api.ControllerHelpers
[FromBody] [FromBody]
public int? Limit { get; set; } public int? Limit { get; set; }
// //Data filter id to use with this list query
// //0 or less means no filter
// [FromBody]
// public long DataFilterId { get; set; }
public bool? Mini { get; set; }
[FromBody, Required] [FromBody, Required]
public string DataListKey { get; set; } public string DataListKey { get; set; }
[FromBody] [FromBody]
public string FilterJson { get; set; } public string ListView { get; set; }//optional, if null or empty will use default list view built into DataList
[FromBody]
public string SortJson { get; set; }
} }

View File

@@ -1,4 +1,5 @@
using System.Collections.Generic; using System.Collections.Generic;
using Newtonsoft.Json.Linq;
using AyaNova.Biz; using AyaNova.Biz;
namespace AyaNova.DataList namespace AyaNova.DataList
{ {
@@ -7,18 +8,52 @@ namespace AyaNova.DataList
//No JOINS just straight up widgets //No JOINS just straight up widgets
public TestWidgetDataList() public TestWidgetDataList()
{ {
ListKey = nameof(TestWidgetDataList);
DefaultListObjectType = AyaType.Widget; DefaultListObjectType = AyaType.Widget;
SQLFrom = "from awidget left outer join auser on (awidget.userid=auser.id)"; SQLFrom = "from awidget left outer join auser on (awidget.userid=auser.id)";
FullListAllowedRoles = BizRoles.GetRoleSet(DefaultListObjectType).ReadFullRecord; AllowedRoles = BizRoles.GetRoleSet(DefaultListObjectType).ReadFullRecord;
MiniListAllowedRoles = AuthorizationRoles.All;//anyone (so can select on forms)
DefaultDataListDisplayTemplate = @" //Default ListView
{ dynamic dlistView = new JArray();
""full"":[""widgetname"",""widgetserial"",""widgetdollaramount"",""widgetusertype"",""widgetstartdate"",""widgetactive"",""username""], dynamic cm=new JObject();
""mini"":[""widgetname"",""widgetserial""] cm.fld="widgetname";
} dlistView.Add(cm);
"; cm=new JObject();
cm.fld="widgetname";
dlistView.Add(cm);
cm=new JObject();
cm.fld="widgetname";
dlistView.Add(cm);
cm=new JObject();
cm.fld="widgetname";
dlistView.Add(cm);
cm=new JObject();
cm.fld="widgetname";
dlistView.Add(cm);
cm=new JObject();
cm.fld="widgetname";
dlistView.Add(cm);
cm=new JObject();
cm.fld="widgetname";
dlistView.Add(cm);
// //name starts with filter to constrict to widgets that this test block created only
// dynamic DataFilterNameStart = new JObject();
// DataFilterNameStart.fld = "widgetname";
// DataFilterNameStart.op = Util.OpStartsWith;
// DataFilterNameStart.value = WidgetNameStart;
// dfilter.Add(DataFilterNameStart);
// DefaultDataListView = @"
// {
// [{key:""COLUMN UNIQUE KEY ID",sort:"-" or "+",filter:{any:true/false,items:[{FILTER OBJECT SEE BELOW}]} }, {key:"second column unique key"},{...etc...}]
// ""full"":[""widgetname"",""widgetserial"",""widgetdollaramount"",""widgetusertype"",""widgetstartdate"",""widgetactive"",""username""],
// }
// ";
//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 //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<AyaDataListFieldDefinition>(); FieldDefinitions = new List<AyaDataListFieldDefinition>();