| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231 | using InABox.Clients;using InABox.Core;using InABox.Scripting;using System;using System.Collections.Generic;using System.Diagnostics.CodeAnalysis;using System.Linq;using System.Text;using System.Threading.Tasks;namespace InABox.Wpf.Dashboard;public interface IDynamicDashboardTable{    string Key { get; set; }    IEnumerable<CoreColumn> GetColumns(DynamicDashboardDataComponent data);}public interface IDynamicDashboardDataQuery : IDynamicDashboardTable{    Type Type { get; }    IFilter? Filter { get; set; }    IColumns Columns { get; set; }    ISortOrder? SortOrder { get; set; }    IEnumerable<CoreColumn> IDynamicDashboardTable.GetColumns(DynamicDashboardDataComponent data) =>        Columns.Columns().Select(x => new CoreColumn        {            ColumnName = x.Name,            DataType = x.Type        });}public class DynamicDashboardDataQuery<T> : IDynamicDashboardDataQuery    where T : Entity, IRemotable, new(){    public string Key { get; set; } = typeof(T).Name;    public Filter<T>? Filter { get; set; }    public Columns<T> Columns { get; set; } = Core.Columns.None<T>();    public SortOrder<T>? SortOrder { get; set; } = null;    #region IDynamicDashboardDataQuery    Type IDynamicDashboardDataQuery.Type => typeof(T);    IFilter? IDynamicDashboardDataQuery.Filter    {        get => Filter;        set => Filter = value as Filter<T>;    }    IColumns IDynamicDashboardDataQuery.Columns    {        get => Columns;        set => Columns = (value as Columns<T>) ?? Core.Columns.None<T>();    }    ISortOrder? IDynamicDashboardDataQuery.SortOrder    {        get => SortOrder;        set => SortOrder = value as SortOrder<T>;    }    #endregion}public class DynamicDashboardAdditionalTable : IDynamicDashboardTable{    public string Key { get; set; } = "";    private string? _script;    public string? Script    {        get => _script;        set        {            if(_script != value)            {                _script = value;                _scriptDocument = null;            }        }    }    public IEnumerable<CoreColumn> GetColumns(DynamicDashboardDataComponent data) => SetupColumns(data);    private ScriptDocument? _scriptDocument;    private ScriptDocument? ScriptDocument    {        get        {            if(_scriptDocument is null && Script is not null)            {                _scriptDocument = new(Script);                _scriptDocument.Compile();            }            return _scriptDocument;        }    }    public static string DefaultScript()    {        return @"using InABox.Wpf.Dashboard;public class Module{    public IEnumerable<CoreColumn> SetupColumns(DynamicDashboardDataComponent data)    {        // Return the list of columns for this table.        return [            new CoreColumn(typeof(string), ""Column1""),            new CoreColumn(typeof(int), ""Column2"")];    }    public void PopulateTable(CoreTable table, DynamicDashboardData data)    {        // Populate 'table' using the data from 'data'.                // For example, to add rows to the table:        var newRow = table.NewRow();        newRow[""Column1""] = ""First Column Data"";        newRow[""Column2""] = 1;        table.Rows.Add(newRow);    }}";    }    private IEnumerable<CoreColumn> SetupColumns(DynamicDashboardDataComponent data)    {        if (ScriptDocument is null) return [];        var method = ScriptDocument.GetMethod(methodName: "SetupColumns");        if(method is not null)        {            return method.Invoke(ScriptDocument!.GetObject(), [data]) as IEnumerable<CoreColumn>                ?? [];        }        else        {            return [];        }    }    public void PopulateTable(CoreTable table, DynamicDashboardData data)    {        if (ScriptDocument is null) return;        ScriptDocument.Execute(methodname: "PopulateTable", parameters: [table, data]);    }}public class DynamicDashboardDataComponent{    public List<IDynamicDashboardDataQuery> Queries { get; set; } = new();    public List<DynamicDashboardAdditionalTable> AdditionalTables { get; set; } = new();    public IEnumerable<IDynamicDashboardTable> Tables => Queries.Concat<IDynamicDashboardTable>(AdditionalTables);    public IDynamicDashboardTable GetTable(string key)    {        return Tables.FirstOrDefault(x => x.Key == key)            ?? throw new KeyNotFoundException($"Data table '{key}' does not exist.");    }    public bool TryGetTable(string key, [NotNullWhen(true)] out IDynamicDashboardTable? query)    {        query = Tables.FirstOrDefault(x => x.Key == key);        return query != null;    }    private void PopulateAdditionalTables(DynamicDashboardData data)    {        foreach(var tableDef in AdditionalTables)        {            var table = new CoreTable();            table.Columns.AddRange(tableDef.GetColumns(this));            tableDef.PopulateTable(table, data);            data.Data.Add(tableDef.Key, table);        }    }    /// <summary>    /// Run the query to get the data according to the definitions of <see cref="Queries"/>.    /// </summary>    /// <param name="maxRecords">Set to a non-<see langword="null"/> value to limit the number of records returned. Used for preview mode.</param>    public DynamicDashboardData RunQuery(int? maxRecords = null)    {        var range = maxRecords.HasValue ? CoreRange.Database(maxRecords.Value) : null;        var queryDefs = Queries.Select(x => new KeyedQueryDef(x.Key, x.Type, x.Filter, x.Columns, x.SortOrder, range));        var results = Client.QueryMultiple(queryDefs);        var data = new DynamicDashboardData(results.Results);        PopulateAdditionalTables(data);        return data;    }    /// <summary>    /// Run the query asynchronously to get the data according to the definitions of <see cref="Queries"/>.    /// </summary>    /// <param name="maxRecords">Set to a non-<see langword="null"/> value to limit the number of records returned. Used for preview mode.</param>    public async Task<DynamicDashboardData> RunQueryAsync(int? maxRecords = null)    {        var range = maxRecords.HasValue ? CoreRange.Database(maxRecords.Value) : null;        var queryDefs = Queries.Select(x => new KeyedQueryDef(x.Key, x.Type, x.Filter, x.Columns, x.SortOrder, range));        var results = await Client.QueryMultipleAsync(queryDefs);        var data = new DynamicDashboardData(results.Results);        PopulateAdditionalTables(data);        return data;    }}public class DynamicDashboardData(Dictionary<string, CoreTable> data){    public Dictionary<string, CoreTable> Data { get; set; } = data;    public bool TryGetData(string key, [NotNullWhen(true)] out CoreTable? query)    {        return Data.TryGetValue(key, out query);    }}
 |