DynamicDashboardDataComponent.cs 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. using InABox.Clients;
  2. using InABox.Core;
  3. using InABox.Scripting;
  4. using System;
  5. using System.Collections.Generic;
  6. using System.Diagnostics.CodeAnalysis;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading.Tasks;
  10. namespace InABox.Wpf.Dashboard;
  11. public interface IDynamicDashboardTable
  12. {
  13. string Key { get; set; }
  14. IEnumerable<CoreColumn> CoreColumns { get; }
  15. }
  16. public interface IDynamicDashboardDataQuery : IDynamicDashboardTable
  17. {
  18. Type Type { get; }
  19. IFilter? Filter { get; set; }
  20. IColumns Columns { get; set; }
  21. ISortOrder? SortOrder { get; set; }
  22. IEnumerable<CoreColumn> IDynamicDashboardTable.CoreColumns => Columns.Columns().Select(x => new CoreColumn
  23. {
  24. ColumnName = x.Name,
  25. DataType = x.Type
  26. });
  27. }
  28. public class DynamicDashboardDataQuery<T> : IDynamicDashboardDataQuery
  29. where T : Entity, IRemotable, new()
  30. {
  31. public string Key { get; set; } = typeof(T).Name;
  32. public Filter<T>? Filter { get; set; }
  33. public Columns<T> Columns { get; set; } = Core.Columns.None<T>();
  34. public SortOrder<T>? SortOrder { get; set; } = null;
  35. #region IDynamicDashboardDataQuery
  36. Type IDynamicDashboardDataQuery.Type => typeof(T);
  37. IFilter? IDynamicDashboardDataQuery.Filter
  38. {
  39. get => Filter;
  40. set => Filter = value as Filter<T>;
  41. }
  42. IColumns IDynamicDashboardDataQuery.Columns
  43. {
  44. get => Columns;
  45. set => Columns = (value as Columns<T>) ?? Core.Columns.None<T>();
  46. }
  47. ISortOrder? IDynamicDashboardDataQuery.SortOrder
  48. {
  49. get => SortOrder;
  50. set => SortOrder = value as SortOrder<T>;
  51. }
  52. #endregion
  53. }
  54. public class DynamicDashboardAdditionalTable : IDynamicDashboardTable
  55. {
  56. public string Key { get; set; } = "";
  57. public List<CoreColumn> Columns { get; set; } = new();
  58. private string? _script;
  59. public string? Script
  60. {
  61. get => _script;
  62. set
  63. {
  64. if(_script != value)
  65. {
  66. _script = value;
  67. _scriptDocument = null;
  68. }
  69. }
  70. }
  71. IEnumerable<CoreColumn> IDynamicDashboardTable.CoreColumns => Columns;
  72. private ScriptDocument? _scriptDocument;
  73. private ScriptDocument? ScriptDocument
  74. {
  75. get
  76. {
  77. if(_scriptDocument is null && Script is not null)
  78. {
  79. _scriptDocument = new(Script);
  80. _scriptDocument.Compile();
  81. }
  82. return _scriptDocument;
  83. }
  84. }
  85. public static string DefaultScript()
  86. {
  87. return @"using InABox.Wpf.Dashboard;
  88. public class Module
  89. {
  90. public void PopulateTable(CoreTable table, DynamicDashboardData data)
  91. {
  92. // Populate 'table' using the data from 'data'.
  93. }
  94. }";
  95. }
  96. public void PopulateTable(CoreTable table, DynamicDashboardData data)
  97. {
  98. if (ScriptDocument is null) return;
  99. ScriptDocument.Execute(methodname: "PopulateTable", parameters: [table, data]);
  100. }
  101. }
  102. public class DynamicDashboardDataComponent
  103. {
  104. public List<IDynamicDashboardDataQuery> Queries { get; set; } = new();
  105. public List<DynamicDashboardAdditionalTable> AdditionalTables { get; set; } = new();
  106. public IEnumerable<IDynamicDashboardTable> Tables => Queries.Concat<IDynamicDashboardTable>(AdditionalTables);
  107. public IDynamicDashboardTable GetTable(string key)
  108. {
  109. return Tables.FirstOrDefault(x => x.Key == key)
  110. ?? throw new KeyNotFoundException($"Data table '{key}' does not exist.");
  111. }
  112. public bool TryGetTable(string key, [NotNullWhen(true)] out IDynamicDashboardTable? query)
  113. {
  114. query = Tables.FirstOrDefault(x => x.Key == key);
  115. return query != null;
  116. }
  117. private void PopulateAdditionalTables(DynamicDashboardData data)
  118. {
  119. foreach(var tableDef in AdditionalTables)
  120. {
  121. var table = new CoreTable();
  122. table.Columns.AddRange(tableDef.Columns);
  123. tableDef.PopulateTable(table, data);
  124. data.Data.Add(tableDef.Key, table);
  125. }
  126. }
  127. /// <summary>
  128. /// Run the query to get the data according to the definitions of <see cref="Queries"/>.
  129. /// </summary>
  130. /// <param name="maxRecords">Set to a non-<see langword="null"/> value to limit the number of records returned. Used for preview mode.</param>
  131. public DynamicDashboardData RunQuery(int? maxRecords = null)
  132. {
  133. var range = maxRecords.HasValue ? CoreRange.Database(maxRecords.Value) : null;
  134. var queryDefs = Queries.Select(x => new KeyedQueryDef(x.Key, x.Type, x.Filter, x.Columns, x.SortOrder, range));
  135. var results = Client.QueryMultiple(queryDefs);
  136. var data = new DynamicDashboardData(results.Results);
  137. PopulateAdditionalTables(data);
  138. return data;
  139. }
  140. /// <summary>
  141. /// Run the query asynchronously to get the data according to the definitions of <see cref="Queries"/>.
  142. /// </summary>
  143. /// <param name="maxRecords">Set to a non-<see langword="null"/> value to limit the number of records returned. Used for preview mode.</param>
  144. public async Task<DynamicDashboardData> RunQueryAsync(int? maxRecords = null)
  145. {
  146. var range = maxRecords.HasValue ? CoreRange.Database(maxRecords.Value) : null;
  147. var queryDefs = Queries.Select(x => new KeyedQueryDef(x.Key, x.Type, x.Filter, x.Columns, x.SortOrder, range));
  148. var results = await Client.QueryMultipleAsync(queryDefs);
  149. var data = new DynamicDashboardData(results.Results);
  150. PopulateAdditionalTables(data);
  151. return data;
  152. }
  153. }
  154. public class DynamicDashboardData(Dictionary<string, CoreTable> data)
  155. {
  156. public Dictionary<string, CoreTable> Data { get; set; } = data;
  157. public bool TryGetData(string key, [NotNullWhen(true)] out CoreTable? query)
  158. {
  159. return Data.TryGetValue(key, out query);
  160. }
  161. }