Browse Source

Merge commit 'd198a2e6c1c3158297a413c1b3e2dc322fddcc63' into frank

Frank van den Bos 1 year ago
parent
commit
5bbc3a4a4f

+ 9 - 3
prs.desktop/Dashboards/UtilityDashboard.xaml.cs

@@ -140,7 +140,7 @@ namespace PRSDesktop
 
         private static List<WidgetDashboardElement>? _dashboardElements;
 
-        private string CurrentDashboardName => ((DashboardsTab.SelectedItem as DynamicTabItem)?.Header?.ToString()) ?? "";
+        private string? CurrentDashboardName => DashboardsTab.SelectedTab?.Header?.ToString();
 
         private DynamicFormDesignGrid? CurrentDashboard => CurrentDashboardName != null ? _dashboards.GetValueOrDefault(CurrentDashboardName) : null;
         
@@ -198,7 +198,10 @@ namespace PRSDesktop
 
         public void Refresh()
         {
-            RefreshDashboard(CurrentDashboardName);
+            if(CurrentDashboardName is string name)
+            {
+                RefreshDashboard(name);
+            }
         }
 
         public void Shutdown(CancelEventArgs? cancel)
@@ -683,7 +686,10 @@ namespace PRSDesktop
         private void OnAfterDesign(object sender)
         {
             SaveCurrentDashboard();
-            RefreshDashboard(CurrentDashboardName);
+            if(CurrentDashboardName is string name) // Null-check
+            {
+                RefreshDashboard(name);
+            }
         }
 
         #endregion

+ 22 - 5
prs.desktop/Grids/TimesheetGrid.cs

@@ -16,7 +16,23 @@ namespace PRSDesktop
 {
     public class TimeSheetGridSettings : IUserConfigurationSettings
     {
-        public CoreFilterDefinition CurrentFilter { get; set; }
+        [Obsolete]
+        private CoreFilterDefinition? _currentFilter;
+
+        [Obsolete]
+        public CoreFilterDefinition? CurrentFilter
+        {
+            get => _currentFilter;
+            set
+            {
+                if (value is not null)
+                {
+                    Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+                }
+            }
+        }
+
+        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
     }
 
     public class TimesheetGrid : DynamicDataGrid<TimeSheet>
@@ -37,7 +53,9 @@ namespace PRSDesktop
             base.Init();
 
             _settings = new UserConfiguration<TimeSheetGridSettings>().Load();
-            SelectFilter(_settings.CurrentFilter, false);
+
+            FilterComponent.SetSettings(_settings.Filters, false);
+            FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
 
             ActionColumns.Add(new DynamicMenuColumn(BuildMenu) { Position = DynamicActionColumnPosition.Start });
             ActionColumns.Add(new DynamicMapColumn<TimeSheet>(this, x => x.StartLocation));
@@ -517,10 +535,9 @@ namespace PRSDesktop
             return result;
         }
 
-        protected override void FilterSelected(CoreFilterDefinition filter)
+        private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
         {
-            base.FilterSelected(filter);
-            _settings.CurrentFilter = filter;
+            _settings.Filters = settings;
             new UserConfiguration<TimeSheetGridSettings>().Save(_settings);
         }
     }

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

@@ -170,7 +170,6 @@ namespace PRSDesktop
                 case DatabaseType.Networked:
                     if (App.DatabaseSettings.Protocol == SerializerProtocol.RPC)
                     {
-                        //new RPC stuff (temporary disabled - for enabling when RPC is ready)
                         _transport = new RpcClientSocketTransport(App.DatabaseSettings.URLs);
                         _transport.OnClose += TransportConnectionLost;
                         _transport.OnException += Transport_OnException;

+ 28 - 10
prs.desktop/Panels/Customers/CustomerReceipts.cs

@@ -14,7 +14,23 @@ namespace PRSDesktop;
 
 public class ReceiptGridSettings : IUserConfigurationSettings
 {
-    public CoreFilterDefinition CurrentFilter { get; set; }
+    [Obsolete]
+    private CoreFilterDefinition? _currentFilter;
+
+    [Obsolete]
+    public CoreFilterDefinition? CurrentFilter
+    {
+        get => _currentFilter;
+        set
+        {
+            if (value is not null)
+            {
+                Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+            }
+        }
+    }
+
+    public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
 }
 
 public class CustomerReceipts : DynamicDataGrid<Receipt>, IPanel<Receipt>
@@ -26,6 +42,8 @@ public class CustomerReceipts : DynamicDataGrid<Receipt>, IPanel<Receipt>
     {
         //AddButton("Show All", PRSDesktop.Resources.view.AsBitmapImage(), ToggleView);
         OnBeforeSave += BeforeSave;
+
+        _settings = new UserConfiguration<ReceiptGridSettings>().Load();
     }
 
     protected override void DoReconfigure(FluentList<DynamicGridOption> options)
@@ -37,8 +55,15 @@ public class CustomerReceipts : DynamicDataGrid<Receipt>, IPanel<Receipt>
     protected override void Init()
     {
         base.Init();
-        _settings = new UserConfiguration<ReceiptGridSettings>().Load();
-        SelectFilter(_settings.CurrentFilter, false);
+
+        FilterComponent.SetSettings(_settings.Filters, refresh: false);
+        FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
+    }
+
+    private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
+    {
+        _settings.Filters = settings;
+        new UserConfiguration<ReceiptGridSettings>().Save(_settings);
     }
 
     public bool IsReady { get; set; }
@@ -98,11 +123,4 @@ public class CustomerReceipts : DynamicDataGrid<Receipt>, IPanel<Receipt>
             receipt.Notes = string.Format("Invoice{0} {1}", numbers.Length > 1 ? "s" : "", string.Join(", ", numbers));
         }
     }
-    
-    protected override void FilterSelected(CoreFilterDefinition filter)
-    {
-        base.FilterSelected(filter);
-        _settings.CurrentFilter = filter;
-        new UserConfiguration<ReceiptGridSettings>().Save(_settings);
-    }
 }

+ 23 - 5
prs.desktop/Panels/DataEntry/DataEntryHistory.cs

@@ -1,4 +1,5 @@
 using System;
+using System.Collections.Generic;
 using System.Linq;
 using System.Windows.Controls;
 using System.Windows.Media.Imaging;
@@ -13,7 +14,23 @@ namespace PRSDesktop;
 
 public class DataEntryHistorySettings : IUserConfigurationSettings
 {
-    public CoreFilterDefinition CurrentFilter { get; set; }
+    [Obsolete]
+    private CoreFilterDefinition? _currentFilter;
+
+    [Obsolete]
+    public CoreFilterDefinition? CurrentFilter
+    {
+        get => _currentFilter;
+        set
+        {
+            if (value is not null)
+            {
+                Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+            }
+        }
+    }
+
+    public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
 }
 
 public class DataEntryHistory : DynamicDataGrid<DataEntryDocument>
@@ -22,7 +39,9 @@ public class DataEntryHistory : DynamicDataGrid<DataEntryDocument>
     public DataEntryHistory()
     {
         _settings = new UserConfiguration<DataEntryHistorySettings>().Load();
-        SelectFilter(_settings.CurrentFilter, false);
+
+        FilterComponent.SetSettings(_settings.Filters, false);
+        FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
         
         HiddenColumns.Add(x => x.Tag.ID);
         HiddenColumns.Add(x => x.Tag.AppliesTo);
@@ -46,10 +65,9 @@ public class DataEntryHistory : DynamicDataGrid<DataEntryDocument>
                 : null;
     }
 
-    protected override void FilterSelected(CoreFilterDefinition filter)
+    private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
     {
-        base.FilterSelected(filter);
-        _settings.CurrentFilter = filter;
+        _settings.Filters = settings;
         new UserConfiguration<DataEntryHistorySettings>().Save(_settings);
     }
 

+ 0 - 6
prs.desktop/Panels/Employees/EmployeeGrid.cs

@@ -5,16 +5,12 @@ using System.Drawing;
 using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
-using System.Windows.Media.Imaging;
 using Comal.Classes;
-using FastReport.DataVisualization.Charting;
 using InABox.Clients;
 using InABox.Configuration;
 using InABox.Core;
 using InABox.DynamicGrid;
 using InABox.WPF;
-using PRSDesktop.Panels.Employees;
-using Xceed.Wpf.Toolkit.PropertyGrid;
 
 namespace PRSDesktop
 {
@@ -210,8 +206,6 @@ namespace PRSDesktop
             return false;
         }
 
-        public Employee[] Employees { get; private set; }
-
         private bool ToggleFinishedEmployees(Button btn, CoreRow[] rows)
         {
             ShowAll = !ShowAll;

+ 138 - 131
prs.desktop/Panels/Employees/EmployeePanel.xaml

@@ -10,140 +10,147 @@
              d:DesignHeight="800" d:DesignWidth="1100">
 
     <Grid>
-        <dynamicGrid:DynamicSplitPanel x:Name="SplitPanel" View="Combined" Anchor="Detail" AnchorWidth="400" MasterCaption="Employee List"
-                                       DetailCaption="Employee Details" OnChanged="SplitPanel_OnChanged">
-            
-            <dynamicGrid:DynamicSplitPanel.Header>
-                <Border BorderBrush="Gray" BorderThickness="0.75">
-                    <Label Content="Employee Details" HorizontalContentAlignment="Center"/>
-                </Border>
-            </dynamicGrid:DynamicSplitPanel.Header>
-            
-            <dynamicGrid:DynamicSplitPanel.Master>
-                <local:EmployeeGrid x:Name="Employees" OnSelectItem="Employees_OnOnSelectItem"/>
-            </dynamicGrid:DynamicSplitPanel.Master>
-            
-            <dynamicGrid:DynamicSplitPanel.Detail>
-                
-                <dynamicGrid:DynamicTabControl>
-                    
-                    <dynamicGrid:DynamicTabItem x:Name="InfoTab" Header="General">
-                        
-                        <Grid>
-                            <Grid.RowDefinitions>
-                                <RowDefinition Height="Auto"/>
-                                <RowDefinition Height="300" x:Name="RosterGridRow"/>
-                                <RowDefinition Height="Auto"/>
-                                <RowDefinition Height="*"/>
-                                <!-- <RowDefinition Height="300"/> -->
-                            </Grid.RowDefinitions>
-                            <Grid.ColumnDefinitions>
-                                <ColumnDefinition Width="*"/>
-                            </Grid.ColumnDefinitions>
-                            
-                            <Border Grid.Row="0" BorderThickness="0.75" BorderBrush="DimGray" Background="Gainsboro">
-                                <Label Content="Rosters"  HorizontalContentAlignment="Center"/>
-                            </Border>
-                            
-                            <local:EmployeeRosterItemGrid x:Name="Rosters" Grid.Row="1" OnChanged="Rosters_OnOnChanged" SizeChanged="Rosters_OnSizeChanged" Margin="0,2,0,0"/>
-                            
-                            <syncfusion:SfGridSplitter Grid.Row="2" Grid.Column="0"
-                                                       ResizeBehavior="PreviousAndNext" Height="4" HorizontalAlignment="Stretch"
-                                                       Background="Transparent" Template="{StaticResource HorizontalSplitter}">
+        <dynamicGrid:DynamicTabControl x:Name="Tab" SelectionChanged="Tab_SelectionChanged">
+            <dynamicGrid:DynamicTabItem Header="Employees" x:Name="EmployeeTab">
+                <dynamicGrid:DynamicSplitPanel x:Name="SplitPanel" View="Combined" Anchor="Detail" AnchorWidth="400" MasterCaption="Employee List"
+                                               DetailCaption="Employee Details" OnChanged="SplitPanel_OnChanged">
+
+                    <dynamicGrid:DynamicSplitPanel.Header>
+                        <Border BorderBrush="Gray" BorderThickness="0.75">
+                            <Label Content="Employee Details" HorizontalContentAlignment="Center"/>
+                        </Border>
+                    </dynamicGrid:DynamicSplitPanel.Header>
+
+                    <dynamicGrid:DynamicSplitPanel.Master>
+                        <local:EmployeeGrid x:Name="Employees" OnSelectItem="Employees_OnOnSelectItem"/>
+                    </dynamicGrid:DynamicSplitPanel.Master>
+
+                    <dynamicGrid:DynamicSplitPanel.Detail>
+
+                        <dynamicGrid:DynamicTabControl>
+
+                            <dynamicGrid:DynamicTabItem x:Name="InfoTab" Header="General">
+
+                                <Grid>
+                                    <Grid.RowDefinitions>
+                                        <RowDefinition Height="Auto"/>
+                                        <RowDefinition Height="300" x:Name="RosterGridRow"/>
+                                        <RowDefinition Height="Auto"/>
+                                        <RowDefinition Height="*"/>
+                                        <!-- <RowDefinition Height="300"/> -->
+                                    </Grid.RowDefinitions>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+
+                                    <Border Grid.Row="0" BorderThickness="0.75" BorderBrush="DimGray" Background="Gainsboro">
+                                        <Label Content="Rosters"  HorizontalContentAlignment="Center"/>
+                                    </Border>
+
+                                    <local:EmployeeRosterItemGrid x:Name="Rosters" Grid.Row="1" OnChanged="Rosters_OnOnChanged" SizeChanged="Rosters_OnSizeChanged"
+                                                                  Margin="0,2,0,0"/>
+
+                                    <syncfusion:SfGridSplitter Grid.Row="2" Grid.Column="0"
+                                                               ResizeBehavior="PreviousAndNext" Height="4" HorizontalAlignment="Stretch"
+                                                               Background="Transparent" Template="{StaticResource HorizontalSplitter}">
+
+                                        <syncfusion:SfGridSplitter.PreviewStyle>
+                                            <Style TargetType="Control">
+                                                <Setter Property="Background" Value="Gray" />
+                                                <Setter Property="Template">
+                                                    <Setter.Value>
+                                                        <ControlTemplate TargetType="Control">
+                                                            <Grid x:Name="Root" Opacity="0.5">
+                                                                <Rectangle Fill="{TemplateBinding Background}" />
+                                                            </Grid>
+                                                        </ControlTemplate>
+                                                    </Setter.Value>
+                                                </Setter>
+                                            </Style>
+                                        </syncfusion:SfGridSplitter.PreviewStyle>
+
+                                    </syncfusion:SfGridSplitter>
+
+                                    <DockPanel Grid.Row="3">
+                                        <Border BorderThickness="0.75" BorderBrush="DimGray" DockPanel.Dock="Top" Background="Gainsboro">
+                                            <Label Content="Teams"  HorizontalContentAlignment="Center"/>
+                                        </Border>
+                                        <local:EmployeeTeamGrid x:Name="Teams" DockPanel.Dock="Top" Margin="0,2,0,0" />
+
+                                    </DockPanel>
 
-                                <syncfusion:SfGridSplitter.PreviewStyle>
-                                    <Style TargetType="Control">
-                                        <Setter Property="Background" Value="Gray" />
-                                        <Setter Property="Template">
-                                            <Setter.Value>
-                                                <ControlTemplate TargetType="Control">
-                                                    <Grid x:Name="Root" Opacity="0.5">
-                                                        <Rectangle Fill="{TemplateBinding Background}" />
-                                                    </Grid>
-                                                </ControlTemplate>
-                                            </Setter.Value>
-                                        </Setter>
-                                    </Style>
-                                </syncfusion:SfGridSplitter.PreviewStyle>
-
-                            </syncfusion:SfGridSplitter>
-                            
-                            <DockPanel Grid.Row="3">
-                                <Border BorderThickness="0.75" BorderBrush="DimGray" DockPanel.Dock="Top" Background="Gainsboro">
-                                    <Label Content="Teams"  HorizontalContentAlignment="Center"/>
-                                </Border>
-                                <local:EmployeeTeamGrid x:Name="Teams" DockPanel.Dock="Top" Margin="0,2,0,0" />
-                                
-                            </DockPanel>
-
-                        </Grid>
-                    </dynamicGrid:DynamicTabItem>
-
-                    <dynamicGrid:DynamicTabItem x:Name="RoleTab" Header="Job Roles">
-                
-                        <Grid>
-                            <Grid.RowDefinitions>
-                                <RowDefinition Height="250" x:Name="RoleGridRow"/>
-                                <RowDefinition Height="Auto"/>
-                                <RowDefinition Height="*"/>
-                            </Grid.RowDefinitions>
-                            <Grid.ColumnDefinitions>
-                                <ColumnDefinition Width="*"/>
-                            </Grid.ColumnDefinitions>
-                            
-                            <local:EmployeeRoleGrid Grid.Row="0" Grid.Column="0" x:Name="Roles" OnChanged="Roles_OnOnChanged" SizeChanged="Roles_OnSizeChanged" />
-                            
-                            <syncfusion:SfGridSplitter Grid.Row="1" Grid.Column="0"
+                                </Grid>
+                            </dynamicGrid:DynamicTabItem>
+
+                            <dynamicGrid:DynamicTabItem x:Name="RoleTab" Header="Job Roles">
+
+                                <Grid>
+                                    <Grid.RowDefinitions>
+                                        <RowDefinition Height="250" x:Name="RoleGridRow"/>
+                                        <RowDefinition Height="Auto"/>
+                                        <RowDefinition Height="*"/>
+                                    </Grid.RowDefinitions>
+                                    <Grid.ColumnDefinitions>
+                                        <ColumnDefinition Width="*"/>
+                                    </Grid.ColumnDefinitions>
+
+                                    <local:EmployeeRoleGrid Grid.Row="0" Grid.Column="0" x:Name="Roles" OnChanged="Roles_OnOnChanged" SizeChanged="Roles_OnSizeChanged" />
+
+                                    <syncfusion:SfGridSplitter Grid.Row="1" Grid.Column="0"
                                                        ResizeBehavior="PreviousAndNext" Height="4" HorizontalAlignment="Stretch"
                                                        Background="Transparent" Template="{StaticResource HorizontalSplitter}">
 
-                                <syncfusion:SfGridSplitter.PreviewStyle>
-                                    <Style TargetType="Control">
-                                        <Setter Property="Background" Value="Gray" />
-                                        <Setter Property="Template">
-                                            <Setter.Value>
-                                                <ControlTemplate TargetType="Control">
-                                                    <Grid x:Name="Root" Opacity="0.5">
-                                                        <Rectangle Fill="{TemplateBinding Background}" />
-                                                    </Grid>
-                                                </ControlTemplate>
-                                            </Setter.Value>
-                                        </Setter>
-                                    </Style>
-                                </syncfusion:SfGridSplitter.PreviewStyle>
-
-                            </syncfusion:SfGridSplitter>
-                            
-                            <dynamicGrid:DynamicTabControl Grid.Row="2" TabStripPlacement="Bottom">
-                        
-                                <dynamicGrid:DynamicTabItem x:Name="ActivitiesTab" Header="Activities">
-                                    <local:EmployeeActivityGrid x:Name="Activities" />
-                                </dynamicGrid:DynamicTabItem>
-
-                                <dynamicGrid:DynamicTabItem x:Name="FormsTab" Header="Forms">
-                                    <local:EmployeeRoleFormGrid x:Name="Forms" />
-                                </dynamicGrid:DynamicTabItem>
-                                
-                            </dynamicGrid:DynamicTabControl> 
-                            </Grid>
-                        
-                    </dynamicGrid:DynamicTabItem>
-                    
-                    <dynamicGrid:DynamicTabItem Header="Jobs">
-                        <local:EmployeeJobGrid x:Name="Jobs" />
-                    </dynamicGrid:DynamicTabItem>
-                    
-                    <dynamicGrid:DynamicTabItem x:Name="QualificationsTab" Header="Qualifications">
-                        <local:EmployeeQualificationGrid x:Name="Qualifications" />
-                    </dynamicGrid:DynamicTabItem>
-                    
-                    <dynamicGrid:DynamicTabItem x:Name="SpreadsheetsTab" Header="Spreadsheets">
-                        <local:EmployeeSpreadsheetGrid x:Name="Spreadsheets" />
-                    </dynamicGrid:DynamicTabItem>
-
-                </dynamicGrid:DynamicTabControl>
-            </dynamicGrid:DynamicSplitPanel.Detail>
-        </dynamicGrid:DynamicSplitPanel>
-        
+                                        <syncfusion:SfGridSplitter.PreviewStyle>
+                                            <Style TargetType="Control">
+                                                <Setter Property="Background" Value="Gray" />
+                                                <Setter Property="Template">
+                                                    <Setter.Value>
+                                                        <ControlTemplate TargetType="Control">
+                                                            <Grid x:Name="Root" Opacity="0.5">
+                                                                <Rectangle Fill="{TemplateBinding Background}" />
+                                                            </Grid>
+                                                        </ControlTemplate>
+                                                    </Setter.Value>
+                                                </Setter>
+                                            </Style>
+                                        </syncfusion:SfGridSplitter.PreviewStyle>
+
+                                    </syncfusion:SfGridSplitter>
+
+                                    <dynamicGrid:DynamicTabControl Grid.Row="2" TabStripPlacement="Bottom">
+
+                                        <dynamicGrid:DynamicTabItem x:Name="ActivitiesTab" Header="Activities">
+                                            <local:EmployeeActivityGrid x:Name="Activities" />
+                                        </dynamicGrid:DynamicTabItem>
+
+                                        <dynamicGrid:DynamicTabItem x:Name="FormsTab" Header="Forms">
+                                            <local:EmployeeRoleFormGrid x:Name="Forms" />
+                                        </dynamicGrid:DynamicTabItem>
+
+                                    </dynamicGrid:DynamicTabControl>
+                                </Grid>
+
+                            </dynamicGrid:DynamicTabItem>
+
+                            <dynamicGrid:DynamicTabItem Header="Jobs">
+                                <local:EmployeeJobGrid x:Name="Jobs" />
+                            </dynamicGrid:DynamicTabItem>
+
+                            <dynamicGrid:DynamicTabItem x:Name="QualificationsTab" Header="Qualifications">
+                                <local:EmployeeQualificationGrid x:Name="Qualifications" />
+                            </dynamicGrid:DynamicTabItem>
+
+                            <dynamicGrid:DynamicTabItem x:Name="SpreadsheetsTab" Header="Spreadsheets">
+                                <local:EmployeeSpreadsheetGrid x:Name="Spreadsheets" />
+                            </dynamicGrid:DynamicTabItem>
+
+                        </dynamicGrid:DynamicTabControl>
+                    </dynamicGrid:DynamicSplitPanel.Detail>
+                </dynamicGrid:DynamicSplitPanel>
+            </dynamicGrid:DynamicTabItem>
+            <dynamicGrid:DynamicTabItem Header="Roles" x:Name="RoleCrossTab">
+                <local:EmployeeRoleCrossTab x:Name="EmployeeRoles"/>
+            </dynamicGrid:DynamicTabItem>
+        </dynamicGrid:DynamicTabControl>
     </Grid>
 </UserControl>

+ 31 - 8
prs.desktop/Panels/Employees/EmployeePanel.xaml.cs

@@ -85,7 +85,6 @@ namespace PRSDesktop
 
         public void Setup()
         {
-            
             using (new EventSuppressor(Suppress.Events))
             {
                 DoLoadSettings();
@@ -112,12 +111,34 @@ namespace PRSDesktop
         public void CreateToolbarButtons(IPanelHost host)
         {
         }
-        
-        public void Refresh()
+
+        private void Tab_SelectionChanged(object sender, SelectionChangedEventArgs e)
+        {
+            RefreshCurrentTab();
+        }
+
+        private void RefreshCurrentTab()
+        {
+            if (Tab.SelectedTab == EmployeeTab)
+            {
+                RefreshEmployeeTab();
+            }
+            else if (Tab.SelectedTab == RoleCrossTab)
+            {
+                RefreshRoleTab();
+            }
+        }
+
+        private void RefreshRoleTab()
+        {
+            EmployeeRoles.Refresh(true, true);
+        }
+
+        private void RefreshEmployeeTab()
         {
             Employees.Refresh(false, true);
             Rosters.Refresh(false, true);
-            Teams.Refresh(false,true);
+            Teams.Refresh(false, true);
             Roles.Refresh(false, true);
             Activities.Refresh(false, true);
             Forms.Refresh(false, true);
@@ -126,6 +147,11 @@ namespace PRSDesktop
             Jobs.Refresh(false, true);
         }
 
+        public void Refresh()
+        {
+            RefreshCurrentTab();
+        }
+
         public string SectionName => "Employees";
 
         public DataModel DataModel(Selection selection)
@@ -147,10 +173,7 @@ namespace PRSDesktop
 
         private void Employees_OnOnSelectItem(object sender, DynamicGridSelectionEventArgs e)
         {
-
-            Employee employee = (e.Rows == null) || (e.Rows.Length != 1) 
-                ? new Employee()
-                : e.Rows[0].ToObject<Employee>();
+            var employee = e.Rows?.FirstOrDefault()?.ToObject<Employee>() ?? new Employee();
 
             Rosters.Load(employee, null);
             //Rosters.Refresh(false, true);

+ 61 - 0
prs.desktop/Panels/Employees/EmployeeRoleCrossTab.cs

@@ -0,0 +1,61 @@
+using Comal.Classes;
+using InABox.Configuration;
+using InABox.Core;
+using InABox.DynamicGrid;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRSDesktop
+{
+    public class EmployeeRoleCrossTab : DynamicManyToManyCrossTab<EmployeeRole, Employee, Role>
+    {
+        public DynamicGridFilterButtonComponent<Employee> EmployeeFilter { get; init; }
+
+        public DynamicGridFilterButtonComponent<Role> RoleFilter { get; init; }
+
+        public EmployeeRoleCrossTab()
+        {
+            EmployeeFilter = new(this, new GlobalConfiguration<CoreFilterDefinitions>(nameof(Employee))) { ButtonText = "Employees" };
+            RoleFilter = new(this, new GlobalConfiguration<CoreFilterDefinitions>(nameof(Role))) { ButtonText = "Roles" };
+
+            EmployeeFilter.OnFilterRefresh += () => Refresh(false, true);
+            RoleFilter.OnFilterRefresh += () => Refresh(true, true);
+        }
+
+        protected override Filter<Employee>? RowFilter()
+        {
+            return EmployeeFilter.GetFilter();
+        }
+
+        protected override Filter<Role>? ColumnFilter()
+        {
+            return RoleFilter.GetFilter();
+        }
+
+        protected override Columns<Role>? LoadColumnColumns()
+        {
+            return new Columns<Role>(x => x.Code);
+        }
+
+        protected override string FormatColumnHeader(CoreRow row)
+        {
+            return row.Get<Role, string>(x => x.Code);
+        }
+
+        protected override SortOrder<Role>? LoadColumnSort()
+        {
+            return null;
+        }
+
+        protected override DynamicGridColumns LoadRowColumns()
+        {
+            var columns = new DynamicGridColumns();
+            columns.Add<Employee, string>(x => x.Code, 100, "Code", "", Alignment.MiddleLeft);
+            columns.Add<Employee, string>(x => x.Name, 100, "Name", "", Alignment.MiddleLeft);
+            return columns;
+        }
+    }
+}

+ 23 - 6
prs.desktop/Panels/Invoices/InvoiceGrid.cs

@@ -11,13 +11,30 @@ using InABox.Wpf.Reports;
 using InABox.WPF;
 using System.Windows.Media.Imaging;
 using InABox.Configuration;
+using System.Collections.Generic;
 
 namespace PRSDesktop
 {
     
     public class InvoiceGridSettings : IUserConfigurationSettings
     {
-        public CoreFilterDefinition CurrentFilter { get; set; }
+        [Obsolete]
+        private CoreFilterDefinition? _currentFilter;
+
+        [Obsolete]
+        public CoreFilterDefinition? CurrentFilter
+        {
+            get => _currentFilter;
+            set
+            {
+                if (value is not null)
+                {
+                    Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+                }
+            }
+        }
+
+        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
     }
     
     public class InvoiceGrid : DynamicDataGrid<Invoice>
@@ -34,8 +51,9 @@ namespace PRSDesktop
             base.Init();
             
             _settings = new UserConfiguration<InvoiceGridSettings>().Load();
-            SelectFilter(_settings.CurrentFilter, false);
-            
+            FilterComponent.SetSettings(_settings.Filters, false);
+            FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
+
             AddButton("Print", PRSDesktop.Resources.printer.AsBitmapImage(), PrintInvoice2);
             AddButton("Email", PRSDesktop.Resources.email.AsBitmapImage(), EmailInvoice2);
             HiddenColumns.Add(x => x.CustomerLink.ID);
@@ -254,10 +272,9 @@ namespace PRSDesktop
             // mailer.SendMessage(msg);
         }
         
-        protected override void FilterSelected(CoreFilterDefinition filter)
+        private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
         {
-            base.FilterSelected(filter);
-            _settings.CurrentFilter = filter;
+            _settings.Filters = settings;
             new UserConfiguration<InvoiceGridSettings>().Save(_settings);
         }
     }

+ 0 - 1
prs.desktop/Panels/Jobs/JobAssignmentPanel.xaml.cs

@@ -4,7 +4,6 @@ using System.Linq;
 using System.Windows.Controls;
 using Comal.Classes;
 using System.ComponentModel;
-using System.ComponentModel;
 using InABox.Core;
 
 namespace PRSDesktop

+ 21 - 5
prs.desktop/Panels/Jobs/JobGrid.cs

@@ -12,7 +12,23 @@ namespace PRSDesktop
 
     public class JobGridSettings : IUserConfigurationSettings
     {
-        public CoreFilterDefinition? CurrentFilter { get; set; }
+        [Obsolete]
+        private CoreFilterDefinition? _currentFilter;
+
+        [Obsolete]
+        public CoreFilterDefinition? CurrentFilter
+        {
+            get => _currentFilter;
+            set
+            {
+                if (value is not null)
+                {
+                    Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+                }
+            }
+        }
+
+        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
     }
 
     public class JobGrid : DynamicDataGrid<Job>
@@ -24,7 +40,8 @@ namespace PRSDesktop
         public JobGrid()
         {
             _settings = new UserConfiguration<JobGridSettings>().Load();
-            SelectFilter(_settings.CurrentFilter, false);
+            FilterComponent.SetSettings(_settings.Filters, false);
+            FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
 
             HiddenColumns.Add(x => x.ID);
             HiddenColumns.Add(x => x.JobNumber);
@@ -112,10 +129,9 @@ namespace PRSDesktop
             return result;
         }
 
-        protected override void FilterSelected(CoreFilterDefinition filter)
+        private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
         {
-            base.FilterSelected(filter);
-            _settings.CurrentFilter = filter;
+            _settings.Filters = settings;
             new UserConfiguration<JobGridSettings>().Save(_settings);
         }
     }

+ 18 - 13
prs.desktop/Panels/Products/Reservation Management/JobRequisitionReviewGrid.cs

@@ -15,12 +15,23 @@ namespace PRSDesktop
 {
     public class JobRequisitionReviewUserSettings : IUserConfigurationSettings
     {
-        public CoreFilterDefinition Filter { get; set; }
+        [Obsolete]
+        private CoreFilterDefinition? _currentFilter;
 
-        public JobRequisitionReviewUserSettings()
+        [Obsolete]
+        public CoreFilterDefinition? CurrentFilter
         {
-            Filter = new CoreFilterDefinition();
+            get => _currentFilter;
+            set
+            {
+                if (value is not null)
+                {
+                    Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+                }
+            }
         }
+
+        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
     }
 
     public delegate void JobRequiItemSelect(CoreRow[] rows);
@@ -38,11 +49,7 @@ namespace PRSDesktop
         public JobRequisitionReviewGrid()
         {
             FilterSettings = new UserConfiguration<JobRequisitionReviewUserSettings>().Load();
-            if (!string.IsNullOrWhiteSpace(FilterSettings.Filter.Name))
-            {
-                SelectedFilter = new(FilterSettings.Filter.Name, Serialization.Deserialize<Filter<JobRequisitionItem>>(FilterSettings.Filter.Filter));
-                UpdateFilterButton(InABox.Wpf.Resources.filter_set, FilterSettings.Filter.Name);
-            }
+            FilterComponent.SetSettings(FilterSettings.Filters, false);
 
             HiddenColumns.Add(x => x.ID);
             HiddenColumns.Add(x => x.Product.ID);
@@ -99,7 +106,7 @@ namespace PRSDesktop
                 empName = table.Rows.FirstOrDefault().Values[1].ToString();
             }
 
-            OnFilterSelected += GridOnFilterSelected;
+            FilterComponent.OnFiltersSelected += GridOnFilterSelected;
         }
         protected override void DoReconfigure(FluentList<DynamicGridOption> options)
         {
@@ -119,12 +126,10 @@ namespace PRSDesktop
                 .EndUpdate();
         }
 
-
-        private bool GridOnFilterSelected(CoreFilterDefinition filter)
+        private void GridOnFilterSelected(DynamicGridSelectedFilterSettings settings)
         {
-            new UserConfiguration<JobRequisitionReviewUserSettings>().Save(new JobRequisitionReviewUserSettings { Filter = filter });
+            new UserConfiguration<JobRequisitionReviewUserSettings>().Save(new JobRequisitionReviewUserSettings { Filters = settings });
             OnGridRefresh?.Invoke();
-            return true;
         }
 
         private void LoadStockMovements()

+ 21 - 5
prs.desktop/Panels/Staging/Setouts/StagingSetoutGrid.cs

@@ -30,7 +30,23 @@ namespace PRSDesktop
     
     public class StagingSetoutGridSettings : IUserConfigurationSettings
     {
-        public CoreFilterDefinition CurrentFilter { get; set; }
+        [Obsolete]
+        private CoreFilterDefinition? _currentFilter;
+
+        [Obsolete]
+        public CoreFilterDefinition? CurrentFilter
+        {
+            get => _currentFilter;
+            set
+            {
+                if (value is not null)
+                {
+                    Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+                }
+            }
+        }
+
+        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
     }
 
     
@@ -223,7 +239,8 @@ namespace PRSDesktop
         {
             base.Init();
             _settings = new UserConfiguration<StagingSetoutGridSettings>().Load();
-            SelectFilter(_settings.CurrentFilter, false);
+            FilterComponent.SetSettings(_settings.Filters, false);
+            FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
         }
 
         protected override void DoReconfigure(FluentList<DynamicGridOption> options)
@@ -471,10 +488,9 @@ namespace PRSDesktop
         //     base.Reload(criteria, columns, ref sort, action);
         // }
         
-        protected override void FilterSelected(CoreFilterDefinition filter)
+        private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
         {
-            base.FilterSelected(filter);
-            _settings.CurrentFilter = filter;
+            _settings.Filters = settings;
             new UserConfiguration<StagingSetoutGridSettings>().Save(_settings);
         }
         

+ 1 - 3
prs.desktop/Panels/StockSummary/StockSummaryGrid.cs

@@ -254,9 +254,7 @@ namespace PRSDesktop
         private Filters<StockSummary> GetFilters() 
         {
             var filters = new Filters<StockSummary>();
-            
-            if (SelectedFilter?.Item2 != null)
-                filters.Add(SelectedFilter.Item2);
+            filters.Add(FilterComponent.GetFilter());
             
             Filter<StockSummary>? _groupfilter = !GroupIDs.Any()
                 ? new Filter<StockSummary>().None()

+ 22 - 9
prs.desktop/Panels/Suppliers/PurchaseOrders/SupplierPurchaseOrders.cs

@@ -11,16 +11,29 @@ using InABox.Configuration;
 using InABox.Core;
 using InABox.DynamicGrid;
 using InABox.WPF;
-using NPOI.SS.Formula.Functions;
-using sun.misc;
-using Syncfusion.UI.Xaml.Diagram.Controls;
 
 namespace PRSDesktop
 {
     
     public class SupplierPurchaseOrdersSettings : IUserConfigurationSettings
     {
-        public CoreFilterDefinition? CurrentFilter { get; set; }
+        [Obsolete]
+        private CoreFilterDefinition? _currentFilter;
+
+        [Obsolete]
+        public CoreFilterDefinition? CurrentFilter
+        {
+            get => _currentFilter;
+            set
+            {
+                if (value is not null)
+                {
+                    Filters = new DynamicGridSelectedFilterSettings(new List<CoreFilterDefinition> { value }, false);
+                }
+            }
+        }
+
+        public DynamicGridSelectedFilterSettings Filters { get; set; } = new();
     }
     
     public class SupplierPurchaseOrders : DynamicDataGrid<PurchaseOrder>
@@ -36,8 +49,9 @@ namespace PRSDesktop
         public SupplierPurchaseOrders()
         {
             _settings = new UserConfiguration<SupplierPurchaseOrdersSettings>().Load();
-            SelectFilter(_settings.CurrentFilter, false);
-            
+            FilterComponent.SetSettings(_settings.Filters, false);
+            FilterComponent.OnFiltersSelected += FilterComponent_OnFilterSelected;
+
             OnEditorValueChanged += SupplierPurchaseOrders_OnEditorValueChanged;
             OnCustomiseEditor += SupplierPurchaseOrders_OnCustomiseEditor;
             
@@ -241,10 +255,9 @@ namespace PRSDesktop
             return LoadItems(rows);
         }
         
-        protected override void FilterSelected(CoreFilterDefinition filter)
+        private void FilterComponent_OnFilterSelected(DynamicGridSelectedFilterSettings settings)
         {
-            base.FilterSelected(filter);
-            _settings.CurrentFilter = filter;
+            _settings.Filters = settings;
             new UserConfiguration<SupplierPurchaseOrdersSettings>().Save(_settings);
         }
     }