فهرست منبع

Issues system

Kenric Nugteren 7 ماه پیش
والد
کامیت
7a24437d95

+ 297 - 0
prs.desktop/Forms/Issues/IssuesGrid.cs

@@ -0,0 +1,297 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Configuration;
+using InABox.Core;
+using InABox.DynamicGrid;
+using InABox.WPF;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace PRSDesktop.Forms.Issues;
+
+public class IssuesGrid : DynamicGrid<Kanban>, ISpecificGrid
+{
+    private readonly int ChunkSize = 500;
+
+    private IClient<Kanban> _client;
+
+    public Func<Type, IClient> ClientFactory { get; set; }
+
+    private IClient<Kanban> Client
+    {
+        get
+        {
+            _client ??= (ClientFactory(typeof(Kanban)) as IClient<Kanban>)!;
+            return _client;
+        }
+    }
+
+    public Guid CustomerID { get; set; }
+
+    public IssuesGrid() : base()
+    {
+        var cols = LookupFactory.DefineColumns<Kanban>();
+
+        // Minimum Columns for Lookup values
+        foreach (var col in cols)
+            HiddenColumns.Add(col);
+
+        ActionColumns.Add(new DynamicMenuColumn(BuildMenu) { Position = DynamicActionColumnPosition.End });
+    }
+
+    protected override void Init()
+    {
+    }
+
+    protected override void DoReconfigure(DynamicGridOptions options)
+    {
+        options.Clear();
+        options.AddRows = true;
+        options.EditRows = true;
+    }
+
+    private void BuildMenu(DynamicMenuColumn column, CoreRow? row)
+    {
+        if (row is null) return;
+
+        var menu = column.GetMenu();
+        menu.AddItem("Add Note", null, row, AddNote_Click);
+        menu.AddItem("Close Issue", null, row, CloseTask_Click);
+    }
+
+    public override Kanban CreateItem()
+    {
+        var item = base.CreateItem();
+        // item.UserProperties["CustomerID"] = CustomerID.ToString();
+        return item;
+    }
+
+    private void AddNote_Click(CoreRow row)
+    {
+        var kanban = row.ToObject<Kanban>();
+    }
+
+    private void CloseTask_Click(CoreRow row)
+    {
+    }
+
+    private Column<Kanban>[] AllowedColumns = [
+        new(x => x.Number),
+        new(x => x.Title),
+        new(x => x.Description),
+        new(x => x.Notes),
+        new(x => x.Type.ID)];
+
+    protected override void CustomiseEditor(Kanban[] items, DynamicGridColumn column, BaseEditor editor)
+    {
+        base.CustomiseEditor(items, column, editor);
+        if(!AllowedColumns.Any(x => x.Property == column.ColumnName))
+        {
+            editor.Editable = editor.Editable.Combine(Editable.Hidden);
+        }
+    }
+
+    public virtual CoreTable LookupValues(DataLookupEditor editor, Type parent, string columnname, BaseObject[]? items)
+    {
+        var client = ClientFactory(editor.Type);
+
+        var filter = LookupFactory.DefineLookupFilter(parent, editor.Type, columnname, items ?? (Array.CreateInstance(parent, 0) as BaseObject[])!);
+        var columns = LookupFactory.DefineLookupColumns(parent, editor.Type, columnname);
+
+        foreach (var key in editor.OtherColumns.Keys)
+            columns.Add(key);
+
+        var sort = LookupFactory.DefineSort(editor.Type);
+        var result = client.Query(filter, columns, sort);
+
+        result.Columns.Add(new CoreColumn { ColumnName = "Display", DataType = typeof(string) });
+        foreach (var row in result.Rows)
+        {
+            row["Display"] = LookupFactory.FormatLookup(parent, editor.Type, row, columnname);
+        }
+
+        return result;
+    }
+
+    protected override void DefineLookups(ILookupEditorControl sender, Kanban[] items, bool async = true)
+    {
+        if (sender.EditorDefinition is not DataLookupEditor editor)
+        {
+            base.DefineLookups(sender, items, async: async);
+            return;
+        }
+
+        var colname = sender.ColumnName;
+        if (async)
+        {
+            Task.Run(() =>
+            {
+                try
+                {
+                    var values = LookupValues(editor, typeof(Kanban), colname, items);
+                    Dispatcher.Invoke(
+                        () =>
+                        {
+                            try
+                            {
+                                //Logger.Send(LogType.Information, typeof(T).Name, "Dispatching Results" + colname);
+                                sender.LoadLookups(values);
+                            }
+                            catch (Exception e2)
+                            {
+                                Logger.Send(LogType.Information, typeof(Kanban).Name,
+                                    "Exception (2) in LoadLookups: " + e2.Message + "\n" + e2.StackTrace);
+                            }
+                        }
+                    );
+                }
+                catch (Exception e)
+                {
+                    Logger.Send(LogType.Information, typeof(Kanban).Name,
+                        "Exception (1) in LoadLookups: " + e.Message + "\n" + e.StackTrace);
+                }
+            });
+        }
+        else
+        {
+            var values = LookupValues(editor, typeof(Kanban), colname, items);
+            sender.LoadLookups(values);
+        }
+    }
+
+    public override DynamicEditorPages LoadEditorPages(Kanban item)
+    {
+        var pages = new DynamicEditorPages
+        {
+            new DynamicDocumentGrid<KanbanDocument, Kanban, KanbanLink>()
+        };
+        return pages;
+    }
+
+    protected override DynamicGridColumns LoadColumns()
+    {
+        var columns = new DynamicGridColumns<Kanban>();
+        columns.Add(x => x.Number);
+        columns.Add(x => x.Title);
+        columns.Add(x => x.Type.Code);
+        return columns;
+    }
+
+    #region Grid Stuff
+
+    protected override string FormatRecordCount(int count)
+    {
+        return IsPaging 
+            ? $"{base.FormatRecordCount(count)} (loading..)"
+            : base.FormatRecordCount(count);
+    }
+
+    protected override void Reload(
+        Filters<Kanban> criteria, Columns<Kanban> columns, ref SortOrder<Kanban>? sort,
+        CancellationToken token, Action<CoreTable?, Exception?> action)
+    {
+        // criteria.Add(new Filter<Kanban>("CustomerID").IsEqualTo(CustomerID.ToString()));
+        if(Options.PageSize > 0)
+        {
+            var inSort = sort;
+            Task.Run(() =>
+            {
+                
+                var page = CoreRange.Database(Options.PageSize);
+                var filter = criteria.Combine();
+                
+                IsPaging = true;
+                while (!token.IsCancellationRequested)
+                {
+                    try
+                    {
+                        var data = Client.Query(filter, columns, inSort, page);
+                        data.Offset = page.Offset;
+                        IsPaging = data.Rows.Count == page.Limit;
+
+                        if (token.IsCancellationRequested)
+                        {
+                            break;
+                        }
+
+                        action(data, null);
+                        if (!IsPaging)
+                            break;
+                        
+                        // Proposal - Let's slow it down a bit to enhance UI responsiveness?
+                        Thread.Sleep(100);
+                        
+                        page.Next();
+                    }
+                    catch (Exception e)
+                    {
+                        action(null, e);
+                        break;
+                    }
+                }
+            }, token);
+        }
+        else
+        {
+            Client.Query(criteria.Combine(), columns, sort, null, action);
+        }
+    }
+
+    public override Kanban[] LoadItems(IList<CoreRow> rows)
+    {
+        var results = new List<Kanban>(rows.Count);
+        for (var i = 0; i < rows.Count; i += ChunkSize)
+        {
+            var chunk = rows.Skip(i).Take(ChunkSize);
+            var filter = new Filter<Kanban>(x => x.ID).InList(chunk.Select(x => x.Get<Kanban, Guid>(x => x.ID)).ToArray());
+
+            var columns = DynamicGridUtils.LoadEditorColumns(Columns.None<Kanban>());
+            var data = Client.Query(filter, columns);
+            results.AddRange(data.ToObjects<Kanban>());
+        }
+
+        return results.ToArray();
+    }
+
+    public override Kanban LoadItem(CoreRow row)
+    {
+        var id = row.Get<Kanban, Guid>(x => x.ID);
+        return Client.Query(
+            new Filter<Kanban>(x => x.ID).IsEqualTo(id),
+            DynamicGridUtils.LoadEditorColumns(Columns.None<Kanban>())).ToObjects<Kanban>().FirstOrDefault()
+            ?? throw new Exception($"No Kanban with ID {id}");
+    }
+
+    public override void SaveItem(Kanban item)
+    {
+        Client.Save(item, "Edited by User");
+    }
+
+    public override void SaveItems(IEnumerable<Kanban> items)
+    {
+        Client.Save(items, "Edited by User");
+    }
+
+    public override void DeleteItems(params CoreRow[] rows)
+    {
+        var deletes = new List<Kanban>();
+        foreach (var row in rows)
+        {
+            var delete = new Kanban
+            {
+                ID = row.Get<Kanban, Guid>(x => x.ID)
+            };
+
+            deletes.Add(delete);
+        }
+
+        Client.Delete(deletes, "Deleted on User Request");
+    }
+
+    #endregion
+}

+ 13 - 0
prs.desktop/Forms/Issues/IssuesWindow.xaml

@@ -0,0 +1,13 @@
+<Window x:Class="PRSDesktop.Forms.Issues.IssuesWindow"
+        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+        xmlns:local="clr-namespace:PRSDesktop.Forms.Issues"
+        mc:Ignorable="d"
+        Title="PRS Issues" Height="450" Width="800"
+        Loaded="Window_Loaded">
+    <Grid Margin="5">
+        <local:IssuesGrid x:Name="Grid"/>
+    </Grid>
+</Window>

+ 53 - 0
prs.desktop/Forms/Issues/IssuesWindow.xaml.cs

@@ -0,0 +1,53 @@
+using Comal.Classes;
+using InABox.Clients;
+using InABox.Rpc;
+using InABox.Wpf;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+
+namespace PRSDesktop.Forms.Issues;
+/// <summary>
+/// Interaction logic for IssuesWindow.xaml
+/// </summary>
+public partial class IssuesWindow : Window
+{
+    public Func<Type, IClient> ClientFactory
+    {
+        set => Grid.ClientFactory = value;
+    }
+
+    public IssuesWindow()
+    {
+        InitializeComponent();
+    }
+
+    private void Window_Loaded(object sender, RoutedEventArgs e)
+    {
+        Grid.Refresh(true, true);
+    }
+
+    public static void Execute()
+    {
+        var transport = new RpcClientSocketTransport(["remote.prsdigital.com.au:8006"]);
+        var client = new RpcClient<Kanban>(transport);
+        if(client.Validate("ADMIN", "admin", Guid.Empty).Status != InABox.Clients.ValidationStatus.VALID)
+        {
+            MessageWindow.ShowMessage("Could not connect to PRS digital database.", "Connection error.");
+            return;
+        }
+        var issues = new IssuesWindow();
+        issues.ClientFactory = x => (Activator.CreateInstance(typeof(RpcClient<>).MakeGenericType(x), transport) as IClient)!;
+        issues.ShowDialog();
+    }
+}

+ 10 - 2
prs.desktop/MainWindow.xaml

@@ -790,6 +790,7 @@
                 <ColumnDefinition Width="*" />
                 <ColumnDefinition Width="*" />
                 <ColumnDefinition Width="*" />
+                <ColumnDefinition Width="*" />
             </Grid.ColumnDefinitions>
 
             <Grid.RowDefinitions>
@@ -805,7 +806,7 @@
                 Margin="0,0,5,0"
                 Background="WhiteSmoke"
                 Grid.Row="0"
-                Grid.Column="2"
+                Grid.Column="3"
                 Size="Middle"
                 Icon="Resources/team.png"
                 HorizontalAlignment="Stretch"
@@ -823,8 +824,15 @@
                            LargeIcon="Resources/contract.png"
                            Click="Forms_Click"
                            Margin="0,0,5,20"/>
+            
+            <fluent:Button Grid.Row="1" Grid.Column="2"
+                           Header="Issues"
+                           LargeIcon="Resources/bug.png"
+                           Click="Issues_Click"
+                           ToolTip="Raise an issue with the PRS team"
+                           Margin="0,0,5,20"/>
 
-            <Border Grid.Row="1" Grid.Column="2" 
+            <Border Grid.Row="1" Grid.Column="3" 
                     BorderBrush="Silver" BorderThickness="0,0.75,0.75,0.75" Padding="0,0,5,20">
                 <StackPanel Orientation="Horizontal">
                     

+ 6 - 1
prs.desktop/MainWindow.xaml.cs

@@ -71,6 +71,7 @@ using System.Windows.Media.Imaging;
 using H.Formatters;
 using PRSDesktop.Panels;
 using Syncfusion.SfSkinManager;
+using PRSDesktop.Forms.Issues;
 
 namespace PRSDesktop;
 
@@ -3597,7 +3598,11 @@ public partial class MainWindow : IPanelHostControl
 
 
 
-    #endregion
 
+    #endregion
 
+    private void Issues_Click(object sender, RoutedEventArgs e)
+    {
+        IssuesWindow.Execute();
+    }
 }

+ 4 - 0
prs.desktop/PRSDesktop.csproj

@@ -45,6 +45,7 @@
     <ItemGroup>
         <None Remove="Resources\001-box.png" />
         <None Remove="Resources\alter.png" />
+        <None Remove="Resources\bug.png" />
         <None Remove="Resources\pdficon.png" />
         <Resource Include="Resources\001-box.png">
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
@@ -115,6 +116,9 @@
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </Resource>
         <None Remove="Resources\certificate.png" />
+        <Resource Include="Resources\bug.png">
+          <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+        </Resource>
         <Resource Include="Resources\certificate.png">
             <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
         </Resource>

+ 10 - 0
prs.desktop/Resources.Designer.cs

@@ -209,6 +209,16 @@ namespace PRSDesktop {
             }
         }
         
+        /// <summary>
+        ///   Looks up a localized resource of type System.Drawing.Bitmap.
+        /// </summary>
+        internal static System.Drawing.Bitmap bug {
+            get {
+                object obj = ResourceManager.GetObject("bug", resourceCulture);
+                return ((System.Drawing.Bitmap)(obj));
+            }
+        }
+        
         /// <summary>
         ///   Looks up a localized resource of type System.Drawing.Bitmap.
         /// </summary>

+ 3 - 0
prs.desktop/Resources.resx

@@ -798,4 +798,7 @@
   <data name="red_up_arrow" type="System.Resources.ResXFileRef, System.Windows.Forms">
     <value>Resources\red_up_arrow.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
   </data>
+  <data name="bug" type="System.Resources.ResXFileRef, System.Windows.Forms">
+    <value>Resources\bug.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
+  </data>
 </root>

BIN
prs.desktop/Resources/bug.png