Browse Source

Merge remote-tracking branch 'origin/kenric' into frank

frogsoftware 1 year ago
parent
commit
05d39f0d85

+ 3 - 1
prs.desktop/Panels/EmployeePlanner/EmployeeResourcePlanner.xaml

@@ -182,7 +182,9 @@
             CanMaintainScrollPosition="True"
             SelectionMode="Extended"
             SelectionForegroundBrush="Yellow"
-            RowSelectionBrush="Red">
+            RowSelectionBrush="Red"
+            ShowToolTip="True"
+            CellToolTipOpening="dataGrid_CellToolTipOpening">
             
             <Syncfusion:SfDataGrid.ContextMenu>
                 <ContextMenu />

+ 202 - 47
prs.desktop/Panels/EmployeePlanner/EmployeeResourcePlanner.xaml.cs

@@ -24,12 +24,15 @@ using Syncfusion.UI.Xaml.Grid;
 using Syncfusion.UI.Xaml.Grid.Helpers;
 using Syncfusion.Windows.Tools.Controls;
 using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
+using System.Windows.Documents;
 
 namespace PRSDesktop;
 
 public class EmployeeResourcePlannerValue
 {
-    public Guid ID { get; set; }
+    public Guid[] IDs { get; set; } = Array.Empty<Guid>();
+
+    public AssignmentModel[] Assignments = Array.Empty<AssignmentModel>();
     
     public Brush Background { get; set; }
     public Brush Foreground { get; set; }
@@ -43,31 +46,59 @@ public class EmployeeResourcePlannerValue
         {
             _color = value;
             var color = String.IsNullOrWhiteSpace(value) ? Colors.Transparent : (Color)ColorConverter.ConvertFromString(value);
-            Background = new SolidColorBrush(color);
+            Background = new SolidColorBrush(color) { Opacity = 0.8 };
             Foreground = new SolidColorBrush(ImageUtils.GetForegroundColor(color));
         }
     }
 }
 
-public partial class EmployeeResourcePlanner : UserControl
+public enum EmployeePlannerDisplayMode
+{
+    EmployeeColumns,
+    DateColumns
+}
+
+public class EmployeeResourcePlannerSettings : BaseObject, IGlobalConfigurationSettings
+{
+    [EnumLookupEditor(typeof(EmployeePlannerDisplayMode))]
+    [EditorSequence(1)]
+    public EmployeePlannerDisplayMode DisplayMode { get; set; }
+
+    public EmployeeResourcePlannerSettings()
+    {
+        DisplayMode = EmployeePlannerDisplayMode.DateColumns;
+    }
+}
+
+public partial class EmployeeResourcePlanner : UserControl, IPropertiesPanel<EmployeeResourcePlannerSettings>
 {
 
     private enum Suppress
     {
         This
     }
-    
+
     private EmployeeResourceModel[] _employees = Array.Empty<EmployeeResourceModel>();
     private StandardLeaveModel[] _standardleaves = Array.Empty<StandardLeaveModel>();
     private LeaveRequestModel[] _leaverequests = Array.Empty<LeaveRequestModel>();
     private JobModel[] _jobs = Array.Empty<JobModel>();
     private ActivityModel[] _activities = Array.Empty<ActivityModel>();
 
+    private DateTime[] _dates = Array.Empty<DateTime>();
+
     private CoreFilterDefinitions _jobfilters = new CoreFilterDefinitions();
     
     public event LoadSettings<EmployeeResourcePlannerProperties> LoadSettings;
     public event SaveSettings<EmployeeResourcePlannerProperties> SaveSettings;
 
+    EmployeeResourcePlannerSettings IPropertiesPanel<EmployeeResourcePlannerSettings>.Properties
+    {
+        get => Settings;
+        set => Settings = value;
+    }
+
+    private EmployeeResourcePlannerSettings Settings { get; set; }
+
     private void DoLoadSettings()
     {
         Properties = LoadSettings?.Invoke(this) ?? new EmployeeResourcePlannerProperties();
@@ -179,48 +210,89 @@ public partial class EmployeeResourcePlanner : UserControl
 
             var assignments = query.Get<Assignment>().Rows.Select(r => new AssignmentModel(r)).ToArray();
 
-
             var data = new DataTable();
-            data.Columns.Add("Date", typeof(DateTime));
+            if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns)
+            {
+                data.Columns.Add("Date", typeof(DateTime));
 
-            foreach (var employee in _employees)
-                data.Columns.Add(employee.ID.ToString(), typeof(object));
+                foreach (var employee in _employees)
+                {
+                    data.Columns.Add(employee.ID.ToString(), typeof(object));
+                }
+
+                for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
+                {
+                    var leavevalue = GetStandardLeave(curdate, _standardleaves);
+                    var values = new List<object> { curdate };
+                    foreach (var employee in _employees)
+                    {
+                        var value = new EmployeeResourcePlannerValue();
+                        // Note use of short-circuiting here.
+                        var bOK = CheckAssignments(employee, curdate, assignments, value)
+                            || CheckRoster(employee, curdate, value)
+                            || CheckStandardLeave(leavevalue, value)
+                            || CheckLeaveRequest(employee, curdate, _leaverequests, value);
+
+                        values.Add(value);
+                    }
 
-            for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
+                    data.Rows.Add(values.ToArray());
+                }
+            }
+            else
             {
-                var leavevalue = GetStandardLeave(curdate, _standardleaves);
-                var values = new List<object> { curdate };
+                data.Columns.Add("Employee", typeof(object));
+
+                var dates = new List<DateTime>();
+                for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
+                {
+                    data.Columns.Add(dates.Count.ToString(), typeof(object));
+                    dates.Add(curdate);
+                }
+                _dates = dates.ToArray();
+
                 foreach (var employee in _employees)
                 {
-                    var value = new EmployeeResourcePlannerValue();
-                    var bOK = CheckAssignments(employee, curdate, assignments, value);
-                    bOK = bOK || CheckRoster(employee, curdate, value);
-                    bOK = bOK || CheckStandardLeave(leavevalue, value);
-                    bOK = bOK || CheckLeaveRequest(employee, curdate, _leaverequests, value);
+                    var values = new List<object> { employee };
+                    for (var curdate = fromdate; curdate <= todate; curdate = curdate.AddDays(1))
+                    {
+                        var leavevalue = GetStandardLeave(curdate, _standardleaves);
+                        var value = new EmployeeResourcePlannerValue();
+                        var bOK = CheckAssignments(employee, curdate, assignments, value);
+                        bOK = bOK || CheckRoster(employee, curdate, value);
+                        bOK = bOK || CheckStandardLeave(leavevalue, value);
+                        bOK = bOK || CheckLeaveRequest(employee, curdate, _leaverequests, value);
+
+                        values.Add(value);
+                    }
 
-                    values.Add(value);
+                    data.Rows.Add(values.ToArray());
                 }
-
-                data.Rows.Add(values.ToArray());
             }
 
+
             dataGrid.ItemsSource = data;
         }
     }
     
-    private bool CheckAssignments(EmployeeResourceModel employee, DateTime curdate, AssignmentModel[] assignments, EmployeeResourcePlannerValue value)
+    private static bool CheckAssignments(EmployeeResourceModel employee, DateTime curdate, AssignmentModel[] assignments, EmployeeResourcePlannerValue value)
     {
-        var assignment = assignments.FirstOrDefault(x => (x.EmployeeID == employee.ID) && (x.Date == curdate.Date));
-        if (assignment == null)
+        var dateAssignments = assignments.Where(x => (x.EmployeeID == employee.ID) && (x.Date == curdate.Date)).ToArray();
+        if (dateAssignments.Length == 0)
             return false;
 
-        value.ID = assignment.ID;
-        value.Text = (value.ID != Guid.Empty) ? assignment.JobNumber : "XX";
-        value.Color = assignment.Color;
+        value.IDs = assignments.Select(x => x.ID).ToArray();
+        value.Text = dateAssignments.Length == 1
+            ? (dateAssignments[0].ID != Guid.Empty ? (dateAssignments[0].JobNumber ?? "") : "XX")
+            : $"{dateAssignments.Length} jobs";
+        value.Assignments = dateAssignments;
+
+        value.Color = Colors.LightGreen.ToString();
+
         return true;
     }
 
-    private bool CheckRoster(EmployeeResourceModel employee, DateTime curdate, EmployeeResourcePlannerValue value)
+    private static bool CheckRoster(EmployeeResourceModel employee, DateTime curdate, EmployeeResourcePlannerValue value)
     {
         value.Text = "";
         var roster = RosterUtils.GetRoster(employee.Roster, employee.Start, curdate);
@@ -240,7 +312,7 @@ public partial class EmployeeResourcePlanner : UserControl
         return roster?.Enabled == false;
     }
     
-    private EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves)
+    private static EmployeeResourcePlannerValue? GetStandardLeave(DateTime curdate, StandardLeaveModel[] standardleaves)
     {
         var standardleave = standardleaves.FirstOrDefault(x => 
             (x.From <= curdate) 
@@ -251,7 +323,7 @@ public partial class EmployeeResourcePlanner : UserControl
             : null;
     }
 
-    private bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value)
+    private static bool CheckStandardLeave(EmployeeResourcePlannerValue? leavevalue, EmployeeResourcePlannerValue value)
     {
         if (leavevalue == null)
             return false;
@@ -266,7 +338,7 @@ public partial class EmployeeResourcePlanner : UserControl
             (c.EmployeeID == employee.ID) 
             && (c.From <= curdate) 
             && (c.To.Add(c.ToTime) > curdate) 
-            && (Properties.IncludeUnApprovedLeave ? true : c.Status == LeaveRequestStatus.Approved));
+            && (Properties.IncludeUnApprovedLeave || c.Status == LeaveRequestStatus.Approved));
 
         if (leaverequest == null)
             return false;
@@ -359,7 +431,14 @@ public partial class EmployeeResourcePlanner : UserControl
         e.Column.ColumnSizer = GridLengthUnitType.None;
 
         var value = (e.Column.ValueBinding as Binding)!;
-        if (value.Path.Path.Equals("Date"))
+        if (value.Path.Path.Equals("Employee"))
+        {
+            e.Column.Width = 150;
+            e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
+            e.Column.AllowFocus = false;
+            e.Column.DisplayBinding = new Binding { Path = new PropertyPath(e.Column.MappingName + ".Name") };
+        }
+        else if (value.Path.Path.Equals("Date"))
         {
             e.Column.Width = 80;
             e.Column.HeaderStyle = Resources["DateHeaderStyle"] as Style;
@@ -376,9 +455,19 @@ public partial class EmployeeResourcePlanner : UserControl
             e.Column.Width = 55;
             e.Column.HeaderStyle = Resources["ContentHeaderStyle"] as Style;
 
-            e.Column.HeaderText = (Guid.TryParse(value.Path.Path, out Guid id))
-                ? _employees.FirstOrDefault(x => String.Equals(x.ID, id))?.Name ?? value.Path.Path
-                : value.Path.Path;
+            if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns)
+            {
+                e.Column.HeaderText = (Guid.TryParse(value.Path.Path, out var id)
+                    ? _employees.FirstOrDefault(x => x.ID == id)?.Name ?? value.Path.Path
+                    : value.Path.Path);
+            }
+            else
+            {
+                if(int.TryParse(value.Path.Path, out var idx))
+                {
+                    e.Column.HeaderText = _dates[idx].ToString("dd/MM/yyyy");
+                }
+            }
 
             e.Column.DisplayBinding = new Binding { Path = new PropertyPath(e.Column.MappingName), Converter = new EmployeeResourcePlannerContentConverter() };
             //e.Column.ValueBinding = new Binding() { Path = new PropertyPath(e.Column.MappingName), Converter = new LeaveContentConverter() };
@@ -397,7 +486,7 @@ public partial class EmployeeResourcePlanner : UserControl
                 continue;
             var propertyCollection = dataGrid.View.GetPropertyAccessProvider();
             var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName);
-            if (cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty)
+            if (cellValue is EmployeeResourcePlannerValue val && val.IDs.Length > 0)
                 return true;
         }
 
@@ -410,7 +499,7 @@ public partial class EmployeeResourcePlanner : UserControl
             return false;
         var propertyCollection = dataGrid.View.GetPropertyAccessProvider();
         var cellValue = propertyCollection.GetValue(cell.RowData, cell.Column.MappingName);
-        return cellValue is EmployeeResourcePlannerValue val && val.ID != Guid.Empty;
+        return cellValue is EmployeeResourcePlannerValue val && val.IDs.Length > 0;
     }
 
     private void DataGrid_ContextMenuOpening(object sender, ContextMenuEventArgs e)
@@ -455,6 +544,46 @@ public partial class EmployeeResourcePlanner : UserControl
         }
         
     }
+
+    private void dataGrid_CellToolTipOpening(object sender, GridCellToolTipOpeningEventArgs e)
+    {
+        var record = (e.Record as DataRowView)?[e.Column.MappingName];
+        if (record is not EmployeeResourcePlannerValue value) return;
+
+        if(value.IDs.Length > 0)
+        {
+            e.ToolTip.Template = TemplateGenerator.CreateControlTemplate(
+                typeof(ToolTip),
+                () =>
+                {
+                    var border = new Border
+                    {
+                        BorderBrush = new SolidColorBrush(Colors.Gray),
+                        BorderThickness = new Thickness(0.75),
+                        CornerRadius = new CornerRadius(5),
+                        Background = new SolidColorBrush(Colors.LightYellow),
+                        Padding = new Thickness(5),
+                    };
+                    var panel = new StackPanel();
+                    foreach (var assignment in value.Assignments)
+                    {
+                        var textBlock = new TextBlock();
+                        textBlock.Inlines.Add(new Run
+                        {
+                            Text = assignment.JobNumber,
+                            FontWeight = FontWeights.Bold
+                        });
+                        textBlock.Inlines.Add(new Run
+                        {
+                            Text = $": {assignment.EffectiveStart():hh':'mm} - {assignment.EffectiveFinish():hh':'mm}"
+                        });
+                        panel.Children.Add(textBlock);
+                    }
+                    border.Child = panel;
+                    return border;
+                });
+        }
+    }
     
     private void GetSelectionData(out DateTime from, out DateTime to, out Guid[] employees, out Guid[] assignments)
     {
@@ -464,19 +593,45 @@ public partial class EmployeeResourcePlanner : UserControl
         to = DateTime.MinValue;
         foreach (var cell in dataGrid.GetSelectedCells())
         {
-            var binding = (cell.Column.ValueBinding as Binding)!;
-            if (Guid.TryParse(binding.Path.Path, out var emp))
-                if (!emps.Contains(emp))
-                    emps.Add(emp);
             var row = (cell.RowData as DataRowView)!;
-            var date = (DateTime)row.Row.ItemArray.First()!;
-            if (date < from)
-                from = date;
-            if (date > to)
-                to = date;
-            Guid itemid = (row[binding.Path.Path] as EmployeeResourcePlannerValue).ID;
-            if (itemid != Guid.Empty)
-                items.Add(itemid);
+            var binding = (cell.Column.ValueBinding as Binding)!;
+
+            DateTime date;
+            if(Settings.DisplayMode == EmployeePlannerDisplayMode.EmployeeColumns)
+            {
+                if (Guid.TryParse(binding.Path.Path, out var emp))
+                    if (!emps.Contains(emp))
+                        emps.Add(emp);
+
+                date = (DateTime)row.Row.ItemArray.First()!;
+            }
+            else
+            {
+                if(int.TryParse(binding.Path.Path, out var idx))
+                {
+                    date = _dates[idx];
+                }
+                else
+                {
+                    date = DateTime.MinValue;
+                }
+
+                var empID = ((EmployeeResourceModel)row.Row.ItemArray.First()!).ID;
+                if (!emps.Contains(empID))
+                    emps.Add(empID);
+            }
+            if(date != DateTime.MinValue)
+            {
+                if (date < from)
+                    from = date;
+                if (date > to)
+                    to = date;
+            }
+
+            foreach(var id in (row[binding.Path.Path] as EmployeeResourcePlannerValue)!.IDs)
+            {
+                items.Add(id);
+            }
         }
 
         employees = emps.ToArray();

+ 17 - 18
prs.desktop/Panels/EmployeePlanner/EmployeeResourcePlannerProperties.cs

@@ -1,25 +1,24 @@
 using System;
 using InABox.Configuration;
 
-namespace PRSDesktop
+namespace PRSDesktop;
+
+public class EmployeeResourcePlannerProperties : IUserConfigurationSettings, IDashboardProperties
 {
-    public class EmployeeResourcePlannerProperties : IUserConfigurationSettings, IDashboardProperties
-    {
-        public EmployeeSelectorSettings EmployeeSettings { get; set; }
-        
-        public bool IncludeUnApprovedLeave { get; set; }
-        
-        public EmployeeSelectorData EmployeeSelection { get; set; }
-        public Guid ActivityType { get; set; }
-        public String JobFilter { get; set; }
+    public EmployeeSelectorSettings EmployeeSettings { get; set; }
+    
+    public bool IncludeUnApprovedLeave { get; set; }
+    
+    public EmployeeSelectorData EmployeeSelection { get; set; }
+    public Guid ActivityType { get; set; }
+    public String JobFilter { get; set; }
 
-        public EmployeeResourcePlannerProperties()
-        {
-            EmployeeSettings = new EmployeeSelectorSettings();
-            EmployeeSelection = new EmployeeSelectorData();
-            IncludeUnApprovedLeave = false;
-            ActivityType = Guid.Empty;
-            JobFilter = "";
-        }
+    public EmployeeResourcePlannerProperties()
+    {
+        EmployeeSettings = new EmployeeSelectorSettings();
+        EmployeeSelection = new EmployeeSelectorData();
+        IncludeUnApprovedLeave = false;
+        ActivityType = Guid.Empty;
+        JobFilter = "";
     }
 }