Browse Source

Added Filtering for StagingManufactingPacket Groups
Final Touchups to Staging Panel

frogsoftware 1 year ago
parent
commit
52132c9c23

+ 2 - 2
prs.classes/Entities/Staging/Manufacturing/Packet/StagingManufacturingPacket.cs

@@ -44,8 +44,8 @@ namespace Comal.Classes
         {
             Title = "";
             Job = new JobLink();
-            Quantity = 0;
-            BarcodeQuantity = 0;
+            Quantity = 1;
+            BarcodeQuantity = 1;
             StagingSetout = new StagingSetoutLink();    
             Serial = "";
             Watermark = new StagingManufacturingWatermarkLink();

+ 21 - 0
prs.classes/Entities/Staging/Setout/StagingSetout.cs

@@ -18,6 +18,23 @@ namespace Comal.Classes
                 { packet => packet.StagingSetout.ID, setout => setout.ID }
             };
     }
+    
+    public class StagingSetoutUnprocessedPacketsAggregate : CoreAggregate<StagingSetout, StagingManufacturingPacket, Guid>
+    {
+        public override Expression<Func<StagingManufacturingPacket, Guid>> Aggregate => x => x.ID;
+
+        public override AggregateCalculation Calculation => AggregateCalculation.Count;
+        
+        public override Filter<StagingManufacturingPacket>? Filter => 
+            new Filter<StagingManufacturingPacket>(x => x.ManufacturingPacket.ID).IsEqualTo(Guid.Empty);
+
+        public override Dictionary<Expression<Func<StagingManufacturingPacket, object>>, Expression<Func<StagingSetout, object>>> Links =>
+            new Dictionary<Expression<Func<StagingManufacturingPacket, object>>, Expression<Func<StagingSetout, object>>>()
+            {
+                { packet => packet.StagingSetout.ID, setout => setout.ID }
+            };
+    }
+    
     public class StagingUnapprovedDocumentsAggregate : CoreAggregate<StagingSetout, StagingSetoutDocument, Guid>
     {
         public override Expression<Func<StagingSetoutDocument, Guid>> Aggregate => x => x.ID;
@@ -61,6 +78,10 @@ namespace Comal.Classes
         [IntegerEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
         [Aggregate(typeof(StagingSetoutPacketsAggregate))]
         public int Packets { get; set; }
+        
+        [IntegerEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
+        [Aggregate(typeof(StagingSetoutUnprocessedPacketsAggregate))]
+        public int UnprocessedPackets { get; set; }
 
         [IntegerEditor(Editable = Editable.Hidden, Visible = Visible.Optional)]
         [Aggregate(typeof(StagingUnapprovedDocumentsAggregate))]

+ 1 - 1
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketList.xaml

@@ -17,7 +17,7 @@
         <Grid.RowDefinitions>
             <RowDefinition Height="*"/>
         </Grid.RowDefinitions>
-        <ScrollViewer Background="Gray" Padding="5">
+        <ScrollViewer Background="Gray" Padding="2.5">
             <StackPanel x:Name="ManufacturingPacketList"/>
         </ScrollViewer>
     </Grid>

+ 18 - 2
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketList.xaml.cs

@@ -26,6 +26,7 @@ namespace PRSDesktop
     public partial class StagingManufacturingPacketList : UserControl
     {
         public event Action<bool>? OnCollapsed;
+        public event EventHandler Changed;
 
         private StagingSetout? _setout = null;
         
@@ -67,8 +68,19 @@ namespace PRSDesktop
                     }
                     OnCollapsed?.Invoke(Collapsed());
                 }
+
+                Changed?.Invoke(this, EventArgs.Empty);
             }
         }
+        
+        public TimeSpan TimeRequired()
+        {
+            TimeSpan result = TimeSpan.Zero;
+            var packets = ManufacturingPacketList.Children.OfType<StagingManufacturingPacketListItem>();
+            foreach (var packet in packets)
+                result += packet.TimeRequired();
+            return result;
+        }
 
         public StagingManufacturingPacketList()
         {
@@ -83,10 +95,14 @@ namespace PRSDesktop
 
         private void AddItem(StagingManufacturingPacket packet)
         {
-            var item = new StagingManufacturingPacketListItem(packet);
+            var item = new StagingManufacturingPacketListItem(packet)
+            {
+                Margin = new Thickness(0, 0, 1, 2.5),
+                Collapsed = true
+            };
             item.AfterDelete += Item_OnDelete;
             item.OnCollapsed += Item_OnCollapsed;
-            item.Collapsed = true;
+            item.Changed += (sender, args) => Changed?.Invoke(this, EventArgs.Empty);
             ManufacturingPacketList.Children.Add(item);
         }
 

+ 77 - 17
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketListItem.xaml

@@ -18,24 +18,57 @@
                 </DataTrigger>
             </Style.Triggers>
         </Style>
+        
+        <Style x:Key="SeparatorRowStyle" TargetType="RowDefinition">
+            <Style.Setters>
+                <Setter Property="Height" Value="0"/>
+            </Style.Setters>
+            <Style.Triggers>
+                <DataTrigger Binding="{Binding Path=Collapsed, ElementName=Control}" Value="True">
+                    <Setter Property="Height" Value="0"/>
+                </DataTrigger>
+            </Style.Triggers>
+        </Style>
     </UserControl.Resources>
     
-    <Grid Margin="2.5">
-        <Grid.RowDefinitions>
-            <RowDefinition Height="Auto"/>
-            <RowDefinition x:Name="StagesRow" Style="{StaticResource StagesRowStyle}"/>
-        </Grid.RowDefinitions>
-        <Border Padding="5"
+    <Border 
+        Background="WhiteSmoke"
+        BorderBrush="Gray" 
+        BorderThickness="0.75" 
+        CornerRadius="3"
+        Padding="0">
+        
+        <Grid>
+            <Grid.RowDefinitions>
+                <RowDefinition Height="Auto"/>
+                <RowDefinition Style="{StaticResource SeparatorRowStyle}"/>
+                <RowDefinition Style="{StaticResource StagesRowStyle}"/>
+            </Grid.RowDefinitions>
+            
+            <DockPanel 
+                LastChildFill="True"
                 Grid.Row="0"
-                Background="WhiteSmoke"
-                BorderBrush="Black" BorderThickness="1" CornerRadius="3,3,0,0">
-
-            <DockPanel LastChildFill="True">
+                Margin="5">
+                
                 <Button x:Name="CollapseButton"
                         Click="CollapseButton_Click"
                         Margin="0,0,2,0"
                         Width="30" Height="30"
-                        Background="Transparent" BorderBrush="Transparent"/>
+                        Background="Transparent" BorderBrush="Transparent"
+                        DockPanel.Dock="Left"/>
+                
+                <TextBox x:Name="GroupBox"
+                         Background="Transparent"
+                         Height="30"
+                         Width="50"
+                         Margin="0,0,5,0"
+                         IsEnabled="False"
+                         VerticalAlignment="Center" 
+                         VerticalContentAlignment="Center"
+                         HorizontalContentAlignment="Center"
+                         DockPanel.Dock="Left">
+                </TextBox>
+                
                 <Button x:Name="DeleteButton"
                         DockPanel.Dock="Right"
                         Margin="0" Width="30" Height="30"
@@ -54,6 +87,7 @@
                         </Style>
                     </Button.Style>
                 </Button>
+                
                 <Button x:Name="EditButton"
                         DockPanel.Dock="Right"
                         Margin="0,0,2,0" Width="30" Height="30"
@@ -72,6 +106,7 @@
                         </Style>
                     </Button.Style>
                 </Button>
+                
                 <Button Margin="0,0,2,0" Height="30" Padding="5,0"
                         DockPanel.Dock="Right"
                         x:Name="TemplateButton"
@@ -87,6 +122,30 @@
                         </Style>
                     </Button.Style>
                 </Button>
+                
+                <TextBox x:Name="QtyBox"
+                         PreviewTextInput="QtyBox_OnPreviewTextInput"
+                         TextChanged="QtyBox_OnTextChanged"
+                         LostFocus="QtyBox_OnLostFocus"
+                         Background="LightYellow"
+                         Height="30"
+                         Width="50"
+                         Margin="0,0,5,0"
+                         VerticalAlignment="Center" 
+                         VerticalContentAlignment="Center"
+                         HorizontalContentAlignment="Center"
+                         DockPanel.Dock="Right">
+                    <TextBox.Style>
+                        <Style TargetType="TextBox">
+                            <Style.Triggers>
+                                <DataTrigger Binding="{Binding Path=ReadOnly,ElementName=Control}" Value="True">
+                                    <Setter Property="IsEnabled" Value="False"/>
+                                </DataTrigger>
+                            </Style.Triggers>
+                        </Style>
+                    </TextBox.Style>
+                </TextBox>
+                
                 <TextBox x:Name="SerialBox"
                          TextChanged="SerialBox_TextChanged"
                          LostFocus="SerialBox_LostFocus"
@@ -105,11 +164,12 @@
                         </Style>
                     </TextBox.Style>
                 </TextBox>
+                
             </DockPanel>
-        </Border>
-        <Border Grid.Row="1" BorderBrush="Black" BorderThickness="1,0,1,1" CornerRadius="0,0,3,3"
-                Background="White" Padding="5">
-            <ContentControl Name="StagesContainer"/>
-        </Border>
-    </Grid>
+
+            <Border Grid.Row="1" BorderThickness="0,0.75,0,0" BorderBrush="Gray" />
+
+            <ContentControl Grid.Row="2" Margin="5,0,5,5" x:Name="StagesContainer"/>
+        </Grid>
+    </Border>
 </UserControl>

+ 43 - 0
prs.desktop/Panels/Staging/Manufacturing/StagingManufacturingPacketListItem.xaml.cs

@@ -53,7 +53,19 @@ namespace PRSDesktop
 
         private StagingManufacturingPacketStageGrid StagesGrid;
 
+        public event EventHandler Changed;
+
         private bool _serialChanged = false;
+        private bool _qtychanged = false;
+
+        public TimeSpan TimeRequired()
+        {
+            long result = 0L;
+            var times = StagesGrid.Data.ExtractValues<StagingManufacturingPacketStage, TimeSpan>(x => x.Time);
+            foreach (var time in times)
+                result += time.Ticks;
+            return TimeSpan.FromTicks(result * Packet.Quantity);
+        }
 
         public bool Collapsed
         {
@@ -85,9 +97,13 @@ namespace PRSDesktop
             {
                 Packet = Packet
             };
+            StagesGrid.AfterRefresh += (sender, args) => Changed?.Invoke(this, EventArgs.Empty); 
+            StagesGrid.OnChanged += (sender, args) => Changed?.Invoke(this, EventArgs.Empty); 
             StagesGrid.Refresh(true, true);
 
+            GroupBox.Text = Packet.Group.Code;
             SerialBox.Text = Packet.Serial;
+            QtyBox.Text = Packet.Quantity.ToString();
 
             StagesContainer.Content = StagesGrid;
 
@@ -110,7 +126,9 @@ namespace PRSDesktop
             var oldTemplate = Packet.Template.ID;
             if(grid.EditItems(new object[] { Packet }))
             {
+                GroupBox.Text = Packet.Group.Code;
                 SerialBox.Text = Packet.Serial;
+                QtyBox.Text = Packet.Quantity.ToString();
                 if (Packet.Template.ID != oldTemplate)
                 {
                     UpdateStages();
@@ -226,6 +244,7 @@ namespace PRSDesktop
                 Packet.Serial = SerialBox.Text;
                 SaveTemplate();
                 _serialChanged = false;
+                Changed?.Invoke(this, EventArgs.Empty); 
             }
         }
 
@@ -265,5 +284,29 @@ namespace PRSDesktop
             var readOnly = (bool)e.NewValue;
             item.StagesGrid.ReadOnly = readOnly;
         }
+
+        private void QtyBox_OnPreviewTextInput(object sender, TextCompositionEventArgs e)
+        {
+            if (!int.TryParse(e.Text, out int _))
+                e.Handled = true;
+        }
+        
+        private void QtyBox_OnTextChanged(object sender, TextChangedEventArgs e)
+        {
+            _qtychanged = true;
+        }
+
+        private void QtyBox_OnLostFocus(object sender, RoutedEventArgs e)
+        {
+            if (_qtychanged)
+            {
+                int.TryParse(QtyBox.Text, out int qty);
+                Packet.Quantity = qty;
+                SaveTemplate();
+                _qtychanged = false;
+                Changed?.Invoke(this, EventArgs.Empty); 
+            }
+        }
+        
     }
 }

+ 96 - 35
prs.desktop/Panels/Staging/Setouts/StagingSetoutGrid.cs

@@ -23,11 +23,21 @@ using System.ComponentModel;
 using com.sun.org.apache.xalan.@internal.xsltc.cmdline.getopt;
 using InABox.WPF;
 using System.Windows.Media.Imaging;
+using InABox.Configuration;
+using NPOI.HSSF.Util;
 
 namespace PRSDesktop
 {
+    
+    public class StagingSetoutGridSettings : IUserConfigurationSettings
+    {
+        public CoreFilterDefinition CurrentFilter { get; set; }
+    }
+
+    
     public class StagingSetoutGrid : DynamicDataGrid<StagingSetout>
     {
+        
         public class SetoutDocument
         {
             public Document Document { get; set; }
@@ -46,11 +56,19 @@ namespace PRSDesktop
                 setout = Setout;
             }
         }
+        
+        private StagingSetoutGridSettings _settings;
+        
         public delegate void CustomiseSetoutsEvent(IReadOnlyList<SetoutDocument> setouts);
 
         public event CustomiseSetoutsEvent? OnCustomiseSetouts;
 
+        private readonly BitmapImage locked = PRSDesktop.Resources.locked.AsBitmapImage();
+        private readonly BitmapImage docs = PRSDesktop.Resources.design.AsBitmapImage();
+        private readonly BitmapImage packets = PRSDesktop.Resources.factory.AsBitmapImage();
         private readonly BitmapImage tick = PRSDesktop.Resources.tick.AsBitmapImage();
+        private readonly BitmapImage warning = PRSDesktop.Resources.warning.AsBitmapImage();
+        private readonly BitmapImage rejected = PRSDesktop.Resources.disabled.AsBitmapImage();
 
         public StagingSetoutGrid()
         {
@@ -61,66 +79,103 @@ namespace PRSDesktop
             HiddenColumns.Add(x => x.Locked);
             HiddenColumns.Add(x => x.SavePath);
             HiddenColumns.Add(x => x.LockedBy.ID);
+            HiddenColumns.Add(x => x.LockedBy.Name);
             HiddenColumns.Add(x => x.Packets);
             HiddenColumns.Add(x => x.UnapprovedDocuments);
+            HiddenColumns.Add(x => x.UnprocessedPackets);
+            HiddenColumns.Add(x => x.Task.ID);
 
-            ActionColumns.Add(new DynamicTickColumn<StagingSetout, int>(x => x.Packets, tick, tick, null)
+            ActionColumns.Add(new DynamicTickColumn<StagingSetout,Guid>(x=>x.LockedBy.ID,locked,locked,null)
             {
-                ToolTip = Packets_Tooltip
+                ToolTip = Locked_Tooltip,
+                Position = DynamicActionColumnPosition.Start
             });
+            
             ActionColumns.Add(new DynamicImageColumn(UnapprovedImage)
             {
-                ToolTip = Unapproved_Tooltip
+                ToolTip = Unapproved_Tooltip,
+                Position = DynamicActionColumnPosition.End
             });
 
+            ActionColumns.Add(new DynamicImageColumn(UnprocessedPackets)
+            {
+                ToolTip = Packets_Tooltip,
+                Position = DynamicActionColumnPosition.End
+            });
+            
             AddButton("Create Group", null, CreateGroup);
         }
-
+        
+                
+        private FrameworkElement? Locked_Tooltip(DynamicActionColumn column, CoreRow? row)
+        {
+            if(row is null)
+                return column.TextToolTip("Is this Design Locked?");
+            
+            var islocked = row.Get<StagingSetout, Guid>(x => x.LockedBy.ID);
+            if (islocked != Guid.Empty)
+                return column.TextToolTip($"This design is locked by {row.Get<StagingSetout, String>(x => x.LockedBy.Name)}");
+            
+            return null;
+        }
+        
         private FrameworkElement? Unapproved_Tooltip(DynamicActionColumn column, CoreRow? row)
         {
             if(row is null)
-            {
-                return column.TextToolTip("Approved Documents");
-            }
+                return column.TextToolTip("Is this Design Approved?");
+            
+            var task = row.Get<StagingSetout, Guid>(x => x.Task.ID);
+            if (task != Guid.Empty)
+                return column.TextToolTip("This design has been rejected.");
+            
             var unapproved = row.Get<StagingSetout, int>(x => x.UnapprovedDocuments);
-            if(unapproved == 0)
-            {
-                return column.TextToolTip("This setout has no unapproved documents");
-            }
-            else
-            {
-                return column.TextToolTip($"This setout has {unapproved} documents");
-            }
+            if (unapproved == 0)
+                return column.TextToolTip("This design has been approved."); 
+            
+            return column.TextToolTip($"This design requires checking and approval.");
         }
 
         private FrameworkElement? Packets_Tooltip(DynamicActionColumn column, CoreRow? row)
         {
             if (row is null)
-            {
-                return null;
-            }
-            var packets = row.Get<StagingSetout, int>(x => x.Packets);
-            if (packets == 0)
-            {
-                return column.TextToolTip("This setout has no packets");
-            }
-            else
-            {
-                return column.TextToolTip($"This setout has {packets} packets");
-            }
+                return column.TextToolTip("Manufacturing Packets Status");
+            
+            var packetcount = row.Get<StagingSetout, int>(x => x.Packets);
+            if (packetcount == 0)
+                return column.TextToolTip("This design has no packets defined!");
+            
+            var unprocessed = row.Get<StagingSetout, int>(x => x.UnprocessedPackets);
+            if (unprocessed > 0)
+                return column.TextToolTip($"This design has {unprocessed} unprocessed packet{(unprocessed > 1 ? "s" : "")}.");
+
+            return column.TextToolTip($"All packets for this design have been processed.");
         }
 
         private BitmapImage? UnapprovedImage(CoreRow? arg)
         {
-            if(arg is null)
-            {
-                return null;
-            }
+            if (arg is null)
+                return docs;
+            if (arg.Get<StagingSetout, Guid>(x => x.Task.ID) != Guid.Empty)
+                return rejected;
             if(arg.Get<StagingSetout, int>(x => x.UnapprovedDocuments) == 0)
-            {
                 return tick;
-            }
-            return null;
+            return warning;
+        }
+        
+        private BitmapImage? UnprocessedPackets(CoreRow? arg)
+        {
+            if (arg is null)
+                return packets;
+            if ((arg.Get<StagingSetout, int>(x => x.Packets) > 0) && (arg.Get<StagingSetout, int>(x => x.UnprocessedPackets) == 0))
+                return tick;
+            return warning;
+        }
+
+        protected override void Init()
+        {
+            base.Init();
+            _settings = new UserConfiguration<StagingSetoutGridSettings>().Load();
+            SelectFilter(_settings.CurrentFilter, false);
         }
 
         protected override void DoReconfigure(FluentList<DynamicGridOption> options)
@@ -192,7 +247,7 @@ namespace PRSDesktop
                 var file = ReadFile(x);
                 return new SetoutDocument(file, new StagingSetout
                 {
-                    Number = file.FileName
+                    Number = Path.GetFileNameWithoutExtension(file.FileName)
                 });
             }).ToList();
 
@@ -352,5 +407,11 @@ namespace PRSDesktop
             criteria.Add(new Filter<StagingSetout>(x => x.Archived).IsEqualTo(DateTime.MinValue));
             base.Reload(criteria, columns, ref sort, action);
         }
+        protected override void FilterSelected(CoreFilterDefinition filter)
+        {
+            base.FilterSelected(filter);
+            _settings.CurrentFilter = filter;
+            new UserConfiguration<StagingSetoutGridSettings>().Save(_settings);
+        }
     }
 }

+ 92 - 57
prs.desktop/Panels/Staging/StagingPanel.xaml

@@ -23,7 +23,7 @@
                     <RowDefinition Height="2*"/>
                     <RowDefinition Height="0"/>
                 </Grid.RowDefinitions>
-                <local:StagingSetoutGrid Grid.Row="0" x:Name="stagingSetoutGrid" OnCustomiseSetouts="stagingSetoutGrid_OnCustomiseSetouts"/>
+                <local:StagingSetoutGrid Grid.Row="0" x:Name="stagingSetoutGrid" OnCustomiseSetouts="stagingSetoutGrid_OnCustomiseSetouts" OnDoubleClick="StagingSetoutGrid_OnOnDoubleClick" />
                 <local:StagingMaterialListGrid Grid.Row="1" x:Name="stagingMaterialListGrid"/>
             </Grid>
         </dynamicgrid:DynamicSplitPanel.Master>
@@ -40,54 +40,65 @@
                 </dynamicgrid:DynamicSplitPanel.Header>
                 
                 <dynamicgrid:DynamicSplitPanel.Master>
-                    <Border BorderBrush="Gray" BorderThickness="0.75">
-                        <Grid>
+                    
+                        <Grid Background="WhiteSmoke">
                             <Grid.RowDefinitions>
                                 <RowDefinition Height="*"/>
                                 <RowDefinition Height="Auto"/>
                             </Grid.RowDefinitions>
-                            <ScrollViewer VerticalScrollBarVisibility="Auto" Grid.Row="0">
-                                <StackPanel x:Name="DocumentViewer" Orientation="Vertical" Margin="10"/>
-                            </ScrollViewer>
-                            <Border Grid.Row="1" BorderBrush="Gray" BorderThickness="0.5">
-                                <DockPanel LastChildFill="False">
-                                    <Button DockPanel.Dock="Left"
-                                            Content="Mark Up"
-                                            Padding="20, 5, 20, 5" Margin="5"
-                                            Height="35"
-                                            x:Name="MarkUpButton"
-                                            Click="MarkUpButton_Click"
-                                            IsEnabled="False"/>
-                                    <Button DockPanel.Dock="Right"
-                                            Content="Reject"
-                                            Height="35"
-                                            Padding="20, 5, 20, 5" Margin="5, 5, 15, 5"
-                                            x:Name="RejectButton"
-                                            Click="RejectButton_Click"
-                                            IsEnabled="False"/>
-                                    <Button DockPanel.Dock="Right"
-                                            Content="Approve"
-                                            x:Name="ApproveButton"
-                                            Height="35" Padding="20,5" Margin="5"
-                                            Click="ApproveButton_Click"/>
-                                </DockPanel>
+
+                            <Border BorderBrush="Gray" BorderThickness="0.75" Background="White">
+                                <ScrollViewer VerticalScrollBarVisibility="Auto">
+                                    <StackPanel x:Name="DocumentViewer" Orientation="Vertical" Margin="10"/>
+                                </ScrollViewer>
                             </Border>
+                            
+                            <DockPanel Grid.Row="1" LastChildFill="False" Height="30" Margin="0,2,0,0">
+                                <Button DockPanel.Dock="Left"
+                                        Content="Mark Up"
+                                        Padding="20, 0" Margin="0"
+                                        x:Name="MarkUpButton"
+                                        BorderBrush="Gray" BorderThickness="0.75" 
+                                        Click="MarkUpButton_Click"
+                                        IsEnabled="False"/>
+                                <Button DockPanel.Dock="Right"
+                                        Content="Reject"
+                                        Padding="20, 0" Margin="0"
+                                        x:Name="RejectButton"
+                                        Click="RejectButton_Click"
+                                        BorderBrush="Gray" BorderThickness="0.75" 
+                                        IsEnabled="False"/>
+                                <Button DockPanel.Dock="Right"
+                                        Content="Approve"
+                                        x:Name="ApproveButton"
+                                        Padding="20,0" Margin="0,0,2,0"
+                                        BorderBrush="Gray" BorderThickness="0.75" 
+                                        Click="ApproveButton_Click"/>
+                            </DockPanel>
                         </Grid>
-                    </Border>
+
                 </dynamicgrid:DynamicSplitPanel.Master>
                 
                 <dynamicgrid:DynamicSplitPanel.DetailHeader>
                     <DockPanel LastChildFill="True">
-                        <Button x:Name="CollapsePacketsButton" Click="CollapsePacketsButton_Click"
-                                    Content="Collapse"
-                                    IsEnabled="False"
-                                    DockPanel.Dock="Left"
-                                    Margin="0,0,2,0" Padding="5" Width="75"/>
-                        <Button x:Name="AddPacketButton" Click="AddPacketButton_Click"
-                                    IsEnabled="False"
-                                    DockPanel.Dock="Right"
-                                    Margin="2,0,0,0" Width="30" Height="30">
-                            <Image Source="pack://application:,,,/Resources/add.png"/>
+                        <Button 
+                            x:Name="CollapsePacketsButton" 
+                            Click="CollapsePacketsButton_Click"
+                            Content="Collapse"
+                            IsEnabled="False"
+                            DockPanel.Dock="Left"
+                            Margin="0,0,2,0" 
+                            Width="75"  
+                            BorderBrush="Gray" BorderThickness="0.75"/>
+                        <Button 
+                            x:Name="AddPacketButton" 
+                            Click="AddPacketButton_Click"
+                            IsEnabled="False"
+                            DockPanel.Dock="Right"
+                            Margin="2,0,0,0" 
+                            BorderBrush="Gray" 
+                            BorderThickness="0.75">
+                            <Image Source="pack://application:,,,/Resources/add.png" Height="20" Width="20"/>
                         </Button>
                         <Border BorderBrush="Gray" BorderThickness="0.75" Background="WhiteSmoke"
                                 DockPanel.Dock="Left">
@@ -97,24 +108,48 @@
                 </dynamicgrid:DynamicSplitPanel.DetailHeader>
                 
                 <dynamicgrid:DynamicSplitPanel.Detail>
-                    <Border BorderBrush="Gray" BorderThickness="0.75">
-                        <Grid>
-                            <Grid.RowDefinitions>
-                                <RowDefinition Height="*"/>
-                                <RowDefinition Height="Auto"/>
-                            </Grid.RowDefinitions>
-                            <local:StagingManufacturingPacketList x:Name="ManufacturingPacketList" OnCollapsed="ManufacturingPacketList_OnCollapsed"
-                                                                  Grid.Row="0"/>
-                            <DockPanel LastChildFill="False"
-                                       Grid.Row="1">
-                                <Button DockPanel.Dock="Right"
-                                        Content="Process"
-                                        x:Name="ProcessButton"
-                                        Height="35" Padding="20,5" Margin="5"
-                                        Click="ProcessButton_Click"/>
-                            </DockPanel>
-                        </Grid>
-                    </Border>
+                    <Grid>
+                        <Grid.RowDefinitions>
+                            <RowDefinition Height="*"/>
+                            <RowDefinition Height="Auto"/>
+                        </Grid.RowDefinitions>
+                        <local:StagingManufacturingPacketList x:Name="ManufacturingPacketList" OnCollapsed="ManufacturingPacketList_OnCollapsed"
+                                                              Grid.Row="0" Changed="ManufacturingPacketList_OnChanged"/>
+                        <DockPanel 
+                            LastChildFill="False"
+                            Grid.Row="1"
+                            Margin="0,2,0,0"
+                            Height="30">
+                            <Button 
+                                DockPanel.Dock="Right"
+                                Content="Process"
+                                x:Name="ProcessButton"
+                                Padding="20,0"
+                                BorderBrush="Gray" BorderThickness="0.75" 
+                                Click="ProcessButton_Click"/>
+
+                            <Border BorderBrush="Gray" BorderThickness="0.75" DockPanel.Dock="Left" Padding="10,0">
+                                <StackPanel Orientation="Horizontal" VerticalAlignment="Center">
+                                    <Label
+                                        Content="Total Time"
+                                        HorizontalContentAlignment="Center"
+                                        VerticalContentAlignment="Center"
+                                        Margin="0"
+                                        FontWeight="DemiBold"
+                                        Foreground="Gray"
+                                        Padding="0"/>
+                                    <Label
+                                        x:Name="TimeRequired"
+                                        HorizontalContentAlignment="Center"
+                                        VerticalContentAlignment="Center"
+                                        Margin="5,0,0,0"
+                                        Foreground="Gray"
+                                        Padding="0"/>
+                              </StackPanel>
+                            </Border>
+                        </DockPanel>
+                    </Grid>
+
                 </dynamicgrid:DynamicSplitPanel.Detail>
 
             </dynamicgrid:DynamicSplitPanel>

+ 32 - 3
prs.desktop/Panels/Staging/StagingPanel.xaml.cs

@@ -73,7 +73,7 @@ public class Module
     public partial class StagingPanel : UserControl, IPanel<StagingSetout>
     {
         private StagingPanellSettings _settings = new StagingPanellSettings();
-
+        
         /// <summary>
         /// The currently selected setout.
         /// </summary>
@@ -135,6 +135,7 @@ public class Module
         {
             InitializeComponent();
             SectionName = nameof(StagingPanel);
+            
         }
 
         public void Setup()
@@ -151,6 +152,7 @@ public class Module
             //stagingSetoutGrid.ScanFiles(_settings.SetoutsFolder);
             stagingSetoutGrid.Refresh(true, true);
             stagingSetoutGrid.OnSelectItem += StagingSetoutGrid_OnSelectItem;
+            
         }
 
         private void NestedPanel_OnChanged(object sender, DynamicSplitPanelSettings e)
@@ -286,8 +288,10 @@ public class Module
             new Client<StagingSetout>().Save(selectedSetouts, "Updated from staging screen");
             selectedSetout = null;
             Refresh();
-
+            
             MessageBox.Show(message);
+            MainPanel.View = DynamicSplitPanelView.Combined;
+            NestedPanel.View = DynamicSplitPanelView.Master;
         }
 
         private string ApproveSetout(StagingSetout item, bool bulkapprove)
@@ -634,6 +638,7 @@ public class Module
                         DocumentMode.Complete :
                         DocumentMode.Locked;
             ApproveButton.Content = Document.Approved ? "Unapprove" : "Approve";
+            
         }
 
         public bool IsReady { get; set; }
@@ -734,6 +739,7 @@ public class Module
             Document = null;
 
             ManufacturingPacketList.Setout = null;
+            CalculateTime();
         }
 
         public Dictionary<string, object[]> Selected()
@@ -827,6 +833,29 @@ public class Module
                 });
             }
         }
-        
+
+        private void StagingSetoutGrid_OnOnDoubleClick(object sender, HandledEventArgs args)
+        {
+            ManufacturingPacketList.Setout = selectedSetout;
+            MainPanel.View = DynamicSplitPanelView.Detail;
+            NestedPanel.View = DynamicSplitPanelView.Combined;
+            args.Handled = true;
+        }
+
+        private void CalculateTime()
+        {
+            if (selectedSetout != null)
+            {
+                var time = ManufacturingPacketList.TimeRequired();
+                TimeRequired.Content = $"{time.TotalHours:F2} hours";
+            }
+            else
+                TimeRequired.Content = "N/A";
+        }
+
+        private void ManufacturingPacketList_OnChanged(object? sender, EventArgs e)
+        {
+           CalculateTime();
+        }
     }
 }

+ 1 - 1
prs.desktop/prsdesktop.iss

@@ -5,7 +5,7 @@
 #pragma verboselevel 9
 
 #define MyAppName "PRS Desktop"
-#define MyAppVersion "7.32a"
+#define MyAppVersion "7.32b"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSDesktop.exe"

+ 1 - 1
prs.server/PRSServer.iss

@@ -5,7 +5,7 @@
 #pragma verboselevel 9
 
 #define MyAppName "PRS Server"
-#define MyAppVersion "7.32a"
+#define MyAppVersion "7.32b"
 #define MyAppPublisher "PRS Digital"
 #define MyAppURL "https://www.prs-software.com.au"
 #define MyAppExeName "PRSServer.exe"