Bläddra i källkod

Added ability to create meetings from calendar

Kenric Nugteren 5 dagar sedan
förälder
incheckning
bfe17c047d

+ 1258 - 1228
prs.desktop/Components/Calendar/Calendar.xaml.cs

@@ -21,1533 +21,1563 @@ using PRSDesktop.Grids;
 using Selection = InABox.Core.Selection;
 using SelectionChangedEventArgs = System.Windows.Controls.SelectionChangedEventArgs;
 
-namespace PRSDesktop
+namespace PRSDesktop;
+
+public partial class Calendar
 {
-    public partial class Calendar
+
+    private enum Suppress
     {
+        Selector,  // Prevent the Selector from Being Changed
+        Calendar,  // Prevent the Calendar from Being Reconfigured
+        Events,    // Prevent the Selectors from Responding to Events 
+        Refresh,   // Stop the Data from Being refreshed    
+        Settings   // Dont allow settings to be updated
+    }
 
-        private enum Suppress
-        {
-            Selector,  // Prevent the Selector from Being Changed
-            Calendar,  // Prevent the Calendar from Being Reconfigured
-            Events,    // Prevent the Selectors from Responding to Events 
-            Refresh,   // Stop the Data from Being refreshed    
-            Settings   // Dont allow settings to be updated
-        }
+    private EventSuppressor? suppressor = null;
+    public void DisableUpdate()
+    {
+        suppressor ??= new EventSuppressor(Suppress.Refresh, Suppress.Settings);
+    }
 
-        private EventSuppressor? suppressor = null;
-        public void DisableUpdate()
+    public void EnableUpdate()
+    {
+        if (suppressor != null)
         {
-            suppressor ??= new EventSuppressor(Suppress.Refresh, Suppress.Settings);
+            suppressor.Dispose();
+            suppressor = null;
         }
+    }
 
-        public void EnableUpdate()
-        {
-            if (suppressor != null)
-            {
-                suppressor.Dispose();
-                suppressor = null;
-            }
-        }
+    #region Converters
 
-        #region Converters
+    public static readonly IValueConverter DayOfWeekConverter = new FuncConverter<DateTime, string>(x => x.DayOfWeek.ToString());
 
-        public static readonly IValueConverter DayOfWeekConverter = new FuncConverter<DateTime, string>(x => x.DayOfWeek.ToString());
+    #endregion
 
-        #endregion
+    #region Dependency Properties
 
-        #region Dependency Properties
+    #region HeaderVisibility Dependency Property
 
-        #region HeaderVisibility Dependency Property
+    public static readonly DependencyProperty HeaderVisibilityProperty =
+        DependencyProperty.Register(
+            nameof(HeaderVisibility), 
+            typeof(Visibility), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(Visibility.Collapsed)
+        );
+    
+    public Visibility HeaderVisibility
+    {
+        get => (Visibility)GetValue(HeaderVisibilityProperty);
+        set => SetValue(HeaderVisibilityProperty,value);
+    }
+    
+    #endregion
+    
+    #region SettingsVisible Dependency Property
+    
+    public static readonly DependencyProperty SettingsVisibleProperty =
+        DependencyProperty.Register(
+            nameof(SettingsVisible), 
+            typeof(CalendarSettingsVisibility), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(CalendarSettingsVisibility.Disabled, SettingsVisible_Changed)
+        );
+
+    private static void SettingsVisible_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
+        var value = (CalendarSettingsVisibility)e.NewValue;
 
-        public static readonly DependencyProperty HeaderVisibilityProperty =
-            DependencyProperty.Register(
-                nameof(HeaderVisibility), 
-                typeof(Visibility), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(Visibility.Collapsed)
-            );
-        
-        public Visibility HeaderVisibility
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (Visibility)GetValue(HeaderVisibilityProperty);
-            set => SetValue(HeaderVisibilityProperty,value);
+            calendar.Properties.SettingsVisible = value;
+            calendar.DoSaveSettings();
         }
-        
-        #endregion
-        
-        #region SettingsVisible Dependency Property
-        
-        public static readonly DependencyProperty SettingsVisibleProperty =
-            DependencyProperty.Register(
-                nameof(SettingsVisible), 
-                typeof(CalendarSettingsVisibility), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(CalendarSettingsVisibility.Disabled, SettingsVisible_Changed)
-            );
-
-        private static void SettingsVisible_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
-            var value = (CalendarSettingsVisibility)e.NewValue;
 
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.SettingsVisible = value;
-                calendar.DoSaveSettings();
-            }
+        calendar._splitPanel.View = value == CalendarSettingsVisibility.Visible
+            ? DynamicSplitPanelView.Combined
+            : DynamicSplitPanelView.Master;
+        calendar._splitPanel.AllowableViews = value == CalendarSettingsVisibility.Disabled
+            ? DynamicSplitPanelView.Master
+            : DynamicSplitPanelView.Master | DynamicSplitPanelView.Combined;
+    }
 
-            calendar._splitPanel.View = value == CalendarSettingsVisibility.Visible
-                ? DynamicSplitPanelView.Combined
-                : DynamicSplitPanelView.Master;
-            calendar._splitPanel.AllowableViews = value == CalendarSettingsVisibility.Disabled
-                ? DynamicSplitPanelView.Master
-                : DynamicSplitPanelView.Master | DynamicSplitPanelView.Combined;
-        }
+    public CalendarSettingsVisibility SettingsVisible
+    {
+        get => (CalendarSettingsVisibility)GetValue(SettingsVisibleProperty);
+        set => SetValue(SettingsVisibleProperty, value);
+    }
+    
+    #endregion
+    
+    #region CalendarView Dependency Property
+    
+    public static readonly DependencyProperty CalendarViewProperty =
+        DependencyProperty.Register(
+            nameof(CalendarView), 
+            typeof(CalendarViewType), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(CalendarViewType.Day, CalendarView_Changed)
+        );
+
+    public CalendarViewType CalendarView
+    {
+        get => (CalendarViewType)GetValue(CalendarViewProperty);
+        set => SetValue(CalendarViewProperty, value);
+    }
 
-        public CalendarSettingsVisibility SettingsVisible
-        {
-            get => (CalendarSettingsVisibility)GetValue(SettingsVisibleProperty);
-            set => SetValue(SettingsVisibleProperty, value);
-        }
-        
-        #endregion
-        
-        #region CalendarView Dependency Property
-        
-        public static readonly DependencyProperty CalendarViewProperty =
-            DependencyProperty.Register(
-                nameof(CalendarView), 
-                typeof(CalendarViewType), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(CalendarViewType.Day, CalendarView_Changed)
-            );
+    private static void CalendarView_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public CalendarViewType CalendarView
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (CalendarViewType)GetValue(CalendarViewProperty);
-            set => SetValue(CalendarViewProperty, value);
+            calendar.Properties.CalendarView = calendar.CalendarView;
+            calendar.DoSaveSettings();
         }
 
-        private static void CalendarView_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
-
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.CalendarView = calendar.CalendarView;
-                calendar.DoSaveSettings();
-            }
+        calendar.Refresh();
+    }
 
-            calendar.Refresh();
-        }
+    #endregion
+    
+    #region EmployeeSelector Dependency Property
+    
+    public static readonly DependencyProperty EmployeeSelectionProperty =
+        DependencyProperty.Register(
+            nameof(EmployeeSelection), 
+            typeof(EmployeeSelectorData), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(new EmployeeSelectorData(), EmployeeSelection_Changed)
+        );
+
+    public EmployeeSelectorData EmployeeSelection
+    {
+        get => (EmployeeSelectorData)GetValue(EmployeeSelectionProperty);
+        set => SetValue(EmployeeSelectionProperty, value);
+    }
 
-        #endregion
-        
-        #region EmployeeSelector Dependency Property
-        
-        public static readonly DependencyProperty EmployeeSelectionProperty =
-            DependencyProperty.Register(
-                nameof(EmployeeSelection), 
-                typeof(EmployeeSelectorData), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(new EmployeeSelectorData(), EmployeeSelection_Changed)
-            );
+    private static void EmployeeSelection_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public EmployeeSelectorData EmployeeSelection
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (EmployeeSelectorData)GetValue(EmployeeSelectionProperty);
-            set => SetValue(EmployeeSelectionProperty, value);
+            calendar.Properties.EmployeeSelection = calendar.EmployeeSelection;
+            calendar.DoSaveSettings();
         }
 
-        private static void EmployeeSelection_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
-
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.EmployeeSelection = calendar.EmployeeSelection;
-                calendar.DoSaveSettings();
-            }
+        calendar.EmployeeSelector.Selection = calendar.EmployeeSelection;
+        calendar._employees = calendar.EmployeeSelector.GetEmployeeData((row, rosters) => row.ToObject<Employee>());
+        calendar.ReloadColumns();
+        calendar.Refresh();
+    }
+    
+    private void EmployeeSelector_OnSelectionChanged(object sender, EmployeeSelectorSelectionChangedArgs args)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        EmployeeSelection = args.Selection;
+    }
+    
+    #endregion
+    
+    #region EmployeeSettings Dependency Property
+    
+    public static readonly DependencyProperty EmployeeSettingsProperty =
+        DependencyProperty.Register(
+            nameof(EmployeeSettings), 
+            typeof(EmployeeSelectorSettings), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(new EmployeeSelectorSettings(), EmployeeSettings_Changed)
+        );
+
+    private static void EmployeeSettings_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-            calendar.EmployeeSelector.Selection = calendar.EmployeeSelection;
-            calendar._employees = calendar.EmployeeSelector.GetEmployeeData((row, rosters) => row.ToObject<Employee>());
-            calendar.ReloadColumns();
-            calendar.Refresh();
-        }
-        
-        private void EmployeeSelector_OnSelectionChanged(object sender, EmployeeSelectorSelectionChangedArgs args)
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            EmployeeSelection = args.Selection;
+            calendar.Properties.EmployeeSelector = calendar.EmployeeSettings;
+            calendar.DoSaveSettings();
         }
-        
-        #endregion
-        
-        #region EmployeeSettings Dependency Property
-        
-        public static readonly DependencyProperty EmployeeSettingsProperty =
-            DependencyProperty.Register(
-                nameof(EmployeeSettings), 
-                typeof(EmployeeSelectorSettings), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(new EmployeeSelectorSettings(), EmployeeSettings_Changed)
-            );
-
-        private static void EmployeeSettings_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
+        calendar.EmployeeSelector.Settings = calendar.EmployeeSettings;
+    }
 
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.EmployeeSelector = calendar.EmployeeSettings;
-                calendar.DoSaveSettings();
-            }
-            calendar.EmployeeSelector.Settings = calendar.EmployeeSettings;
-        }
+    public EmployeeSelectorSettings EmployeeSettings
+    {
+        get => (EmployeeSelectorSettings)GetValue(EmployeeSettingsProperty);
+        set => SetValue(EmployeeSettingsProperty, value);
+    }
+    
+    private void EmployeeSelector_OnSettingsChanged(object sender, EmployeeSelectorSettingsChangedArgs args)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        EmployeeSettings = args.Settings;
+    }
 
-        public EmployeeSelectorSettings EmployeeSettings
-        {
-            get => (EmployeeSelectorSettings)GetValue(EmployeeSettingsProperty);
-            set => SetValue(EmployeeSettingsProperty, value);
-        }
-        
-        private void EmployeeSelector_OnSettingsChanged(object sender, EmployeeSelectorSettingsChangedArgs args)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            EmployeeSettings = args.Settings;
-        }
+    #endregion
+    
+    #region TimeInterval DependencyProperty
+    
+    public static readonly DependencyProperty TimeIntervalProperty =
+        DependencyProperty.Register(
+            "TimeInterval", 
+            typeof(CalendarTimeInterval), 
+            typeof(Calendar),
+            new PropertyMetadata(CalendarTimeInterval.FifteenMinutes, TimeInterval_Changed)
+        );
+
+    public CalendarTimeInterval TimeInterval
+    {
+        get => (CalendarTimeInterval)GetValue(TimeIntervalProperty);
+        set => SetValue(TimeIntervalProperty, value);
+    }
 
-        #endregion
-        
-        #region TimeInterval DependencyProperty
-        
-        public static readonly DependencyProperty TimeIntervalProperty =
-            DependencyProperty.Register(
-                "TimeInterval", 
-                typeof(CalendarTimeInterval), 
-                typeof(Calendar),
-                new PropertyMetadata(CalendarTimeInterval.FifteenMinutes, TimeInterval_Changed)
-            );
+    private static void TimeInterval_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public CalendarTimeInterval TimeInterval
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (CalendarTimeInterval)GetValue(TimeIntervalProperty);
-            set => SetValue(TimeIntervalProperty, value);
+            calendar.Properties.TimeInterval = calendar.TimeInterval;
+            calendar.DoSaveSettings();
         }
+        calendar.IntervalSelector.SelectedIndex = (int)calendar.TimeInterval;
 
-        private static void TimeInterval_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
-
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.TimeInterval = calendar.TimeInterval;
-                calendar.DoSaveSettings();
-            }
-            calendar.IntervalSelector.SelectedIndex = (int)calendar.TimeInterval;
+        calendar.CalendarControl.RowInterval = TimeIntervalToTimeSpan(calendar.TimeInterval);
+    }
 
-            calendar.CalendarControl.RowInterval = TimeIntervalToTimeSpan(calendar.TimeInterval);
-        }
+    private void IntervalSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        TimeInterval = (CalendarTimeInterval)IntervalSelector.SelectedIndex;
+    }
 
-        private void IntervalSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            TimeInterval = (CalendarTimeInterval)IntervalSelector.SelectedIndex;
-        }
+    private static TimeSpan TimeIntervalToTimeSpan(CalendarTimeInterval interval)
+    {
+        return interval switch
+        {
+            CalendarTimeInterval.FiveMinutes => new TimeSpan(0, 5, 0),
+            CalendarTimeInterval.SixMinutes => new TimeSpan(0, 6, 0),
+            CalendarTimeInterval.TenMinutes => new TimeSpan(0, 10, 0),
+            CalendarTimeInterval.FifteenMinutes => new TimeSpan(0, 15, 0),
+            CalendarTimeInterval.TwentyMinutes => new TimeSpan(0, 20, 0),
+            CalendarTimeInterval.ThirtyMinutes => new TimeSpan(0, 30, 0),
+            CalendarTimeInterval.SixtyMinutes or _ => new TimeSpan(1, 0, 0)
+        };           
+    }
+    
+    #endregion
+    
+    #region SelectedDate Dependency Property
+    
+    public static readonly DependencyProperty SelectedDateProperty =
+        DependencyProperty.Register(
+            nameof(SelectedDate), 
+            typeof(DateTime), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(DateTime.Today, SelectedDate_Changed)
+        );
+
+    public DateTime SelectedDate
+    {
+        get => (DateTime)GetValue(SelectedDateProperty);
+        set => SetValue(SelectedDateProperty, value);
+    }
 
-        private static TimeSpan TimeIntervalToTimeSpan(CalendarTimeInterval interval)
-        {
-            return interval switch
-            {
-                CalendarTimeInterval.FiveMinutes => new TimeSpan(0, 5, 0),
-                CalendarTimeInterval.SixMinutes => new TimeSpan(0, 6, 0),
-                CalendarTimeInterval.TenMinutes => new TimeSpan(0, 10, 0),
-                CalendarTimeInterval.FifteenMinutes => new TimeSpan(0, 15, 0),
-                CalendarTimeInterval.TwentyMinutes => new TimeSpan(0, 20, 0),
-                CalendarTimeInterval.ThirtyMinutes => new TimeSpan(0, 30, 0),
-                CalendarTimeInterval.SixtyMinutes or _ => new TimeSpan(1, 0, 0)
-            };           
-        }
-        
-        #endregion
-        
-        #region SelectedDate Dependency Property
-        
-        public static readonly DependencyProperty SelectedDateProperty =
-            DependencyProperty.Register(
-                nameof(SelectedDate), 
-                typeof(DateTime), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(DateTime.Today, SelectedDate_Changed)
-            );
+    private static void SelectedDate_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public DateTime SelectedDate
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (DateTime)GetValue(SelectedDateProperty);
-            set => SetValue(SelectedDateProperty, value);
+            calendar.Properties.Date = calendar.SelectedDate;
+            calendar.DoSaveSettings();
         }
 
-        private static void SelectedDate_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
-
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.Date = calendar.SelectedDate;
-                calendar.DoSaveSettings();
-            }
-
-            calendar.Refresh();
-        }
+        calendar.Refresh();
+    }
 
-        public DateTime StartDate => (Properties?.CalendarView ?? CalendarViewType.Day) == CalendarViewType.Day
-            ? SelectedDate
-            : SelectedDate.StartOfWeek(DayOfWeek.Monday);
+    public DateTime StartDate => (Properties?.CalendarView ?? CalendarViewType.Day) == CalendarViewType.Day
+        ? SelectedDate
+        : SelectedDate.StartOfWeek(DayOfWeek.Monday);
+
+    public DateTime EndDate => Properties.CalendarView == CalendarViewType.Day
+        ?  StartDate.AddDays(1)
+        : Properties.CalendarView == CalendarViewType.WorkWeek
+            ? StartDate.AddDays(5)
+            : StartDate.AddDays(7);
+    
+    #endregion
+    
+    #region StartHour Dependency Properties
+    
+    public static readonly DependencyProperty StartHourProperty =
+        DependencyProperty.Register(
+            nameof(StartHour), 
+            typeof(int), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(6, StartHour_Changed, StartHour_Coerce)
+        );
+
+    private static object StartHour_Coerce(DependencyObject d, object baseValue)
+    {
+        if (d is not Calendar calendar || baseValue is not int value) return baseValue;
 
-        public DateTime EndDate => Properties.CalendarView == CalendarViewType.Day
-            ?  StartDate.AddDays(1)
-            : Properties.CalendarView == CalendarViewType.WorkWeek
-                ? StartDate.AddDays(5)
-                : StartDate.AddDays(7);
-        
-        #endregion
-        
-        #region StartHour Dependency Properties
-        
-        public static readonly DependencyProperty StartHourProperty =
-            DependencyProperty.Register(
-                nameof(StartHour), 
-                typeof(int), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(6, StartHour_Changed, StartHour_Coerce)
-            );
+        return Math.Min(calendar.EndHour - 1, Math.Max(0, value));
+    }
 
-        private static object StartHour_Coerce(DependencyObject d, object baseValue)
-        {
-            if (d is not Calendar calendar || baseValue is not int value) return baseValue;
+    public int StartHour
+    {
+        get => (int)GetValue(StartHourProperty);
+        set => SetValue(StartHourProperty, value);
+    }
 
-            return Math.Min(calendar.EndHour - 1, Math.Max(0, value));
-        }
+    private static void StartHour_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public int StartHour
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (int)GetValue(StartHourProperty);
-            set => SetValue(StartHourProperty, value);
+            calendar.Properties.StartHour = calendar.StartHour;
+            calendar.DoSaveSettings();
         }
+        calendar.StartTimeSelector.Text = FormatHour(calendar.StartHour);
+        calendar.CalendarControl.StartHour = TimeSpan.FromHours(calendar.StartHour);
+    }
+    
+    private void StartTimeSelector_Down_Click(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
 
-        private static void StartHour_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
+        StartHour -= 1;
+    }
 
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.StartHour = calendar.StartHour;
-                calendar.DoSaveSettings();
-            }
-            calendar.StartTimeSelector.Text = FormatHour(calendar.StartHour);
-            calendar.CalendarControl.StartHour = TimeSpan.FromHours(calendar.StartHour);
-        }
-        
-        private void StartTimeSelector_Down_Click(object sender, RoutedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
+    private void StartTimeSelector_Up_Click(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
 
-            StartHour -= 1;
-        }
+        StartHour += 1;
+    }
+    
+    #endregion
+    
+    #region End Hour Property
+    
+    public static readonly DependencyProperty EndHourProperty =
+        DependencyProperty.Register(
+            nameof(EndHour), 
+            typeof(int), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(18, EndHour_Changed, EndHour_Coerce)
+        );
+
+    public int EndHour
+    {
+        get => (int)GetValue(EndHourProperty);
+        set => SetValue(EndHourProperty, value);
+    }
 
-        private void StartTimeSelector_Up_Click(object sender, RoutedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
+    private static object EndHour_Coerce(DependencyObject d, object baseValue)
+    {
+        if (d is not Calendar calendar || baseValue is not int value) return baseValue;
 
-            StartHour += 1;
-        }
-        
-        #endregion
-        
-        #region End Hour Property
-        
-        public static readonly DependencyProperty EndHourProperty =
-            DependencyProperty.Register(
-                nameof(EndHour), 
-                typeof(int), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(18, EndHour_Changed, EndHour_Coerce)
-            );
+        return Math.Max(calendar.StartHour + 1, Math.Min(24, value));
+    }
 
-        public int EndHour
-        {
-            get => (int)GetValue(EndHourProperty);
-            set => SetValue(EndHourProperty, value);
-        }
+    private static void EndHour_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        private static object EndHour_Coerce(DependencyObject d, object baseValue)
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            if (d is not Calendar calendar || baseValue is not int value) return baseValue;
-
-            return Math.Max(calendar.StartHour + 1, Math.Min(24, value));
+            calendar.Properties.EndHour = calendar.EndHour;
+            calendar.DoSaveSettings();
         }
+        calendar.FinishTimeSelector.Text = FormatHour(calendar.EndHour);
+        calendar.CalendarControl.EndHour = TimeSpan.FromHours(calendar.EndHour);
+    }
+    
+    private void FinishTimeSelector_Down_Click(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        EndHour -= 1;
+    }
 
-        private static void EndHour_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
-
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.EndHour = calendar.EndHour;
-                calendar.DoSaveSettings();
-            }
-            calendar.FinishTimeSelector.Text = FormatHour(calendar.EndHour);
-            calendar.CalendarControl.EndHour = TimeSpan.FromHours(calendar.EndHour);
-        }
-        
-        private void FinishTimeSelector_Down_Click(object sender, RoutedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            EndHour -= 1;
-        }
+    private void FinishTimeSelector_Up_Click(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        EndHour += 1;
+    }
+    
+    private static string FormatHour(int hour)
+    {
+        return hour <= 0 || hour >= 24
+            ? "Midnight"
+            : hour < 12
+                ? string.Format("{0}:00 AM", hour)
+                : hour > 12
+                    ? string.Format("{0}:00 PM", hour)
+                    : "12:00 NN";
+    }
+    
+    #endregion       
+    
+    #region AssignmentType Dependency Property
+    
+    public static readonly DependencyProperty AssignmentTypeProperty =
+        DependencyProperty.Register(
+            nameof(AssignmentType), 
+            typeof(CalendarAssignmentType), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(CalendarAssignmentType.Booked, AssignmentType_Changed)
+        );
+
+    public CalendarAssignmentType AssignmentType
+    {
+        get => (CalendarAssignmentType)GetValue(AssignmentTypeProperty);
+        set => SetValue(AssignmentTypeProperty, value);
+    }
 
-        private void FinishTimeSelector_Up_Click(object sender, RoutedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            EndHour += 1;
-        }
-        
-        private static string FormatHour(int hour)
-        {
-            return hour <= 0 || hour >= 24
-                ? "Midnight"
-                : hour < 12
-                    ? string.Format("{0}:00 AM", hour)
-                    : hour > 12
-                        ? string.Format("{0}:00 PM", hour)
-                        : "12:00 NN";
-        }
-        
-        #endregion       
-        
-        #region AssignmentType Dependency Property
-        
-        public static readonly DependencyProperty AssignmentTypeProperty =
-            DependencyProperty.Register(
-                nameof(AssignmentType), 
-                typeof(CalendarAssignmentType), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(CalendarAssignmentType.Booked, AssignmentType_Changed)
-            );
+    private static void AssignmentType_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public CalendarAssignmentType AssignmentType
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (CalendarAssignmentType)GetValue(AssignmentTypeProperty);
-            set => SetValue(AssignmentTypeProperty, value);
+            calendar.Properties.AssignmentType = calendar.AssignmentType;
+            calendar.DoSaveSettings();
         }
+        calendar.AssignmentTypeSelector.SelectedIndex = (int)calendar.AssignmentType;
+        calendar.Refresh();
+    }
 
-        private static void AssignmentType_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    private void AssignmentTypeSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        using (new EventSuppressor(Suppress.Selector))
         {
-            if (d is not Calendar calendar) return;
-
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.AssignmentType = calendar.AssignmentType;
-                calendar.DoSaveSettings();
-            }
-            calendar.AssignmentTypeSelector.SelectedIndex = (int)calendar.AssignmentType;
-            calendar.Refresh();
+            AssignmentType = (CalendarAssignmentType)AssignmentTypeSelector.SelectedIndex;
         }
+    }
+    
+    #endregion
+    
+    #region BackgroundType Dependency Property
+    
+    public static readonly DependencyProperty BackgroundTypeProperty =
+        DependencyProperty.Register(
+            nameof(BackgroundType), 
+            typeof(CalendarBackgroundType), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(CalendarBackgroundType.Roster, BackgroundType_Changed)
+        );
+
+    public CalendarBackgroundType BackgroundType
+    {
+        get => (CalendarBackgroundType)GetValue(BackgroundTypeProperty);
+        set => SetValue(BackgroundTypeProperty, value);
+    }
 
-        private void AssignmentTypeSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            using (new EventSuppressor(Suppress.Selector))
-            {
-                AssignmentType = (CalendarAssignmentType)AssignmentTypeSelector.SelectedIndex;
-            }
-        }
-        
-        #endregion
-        
-        #region BackgroundType Dependency Property
-        
-        public static readonly DependencyProperty BackgroundTypeProperty =
-            DependencyProperty.Register(
-                nameof(BackgroundType), 
-                typeof(CalendarBackgroundType), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(CalendarBackgroundType.Roster, BackgroundType_Changed)
-            );
+    private static void BackgroundType_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        public CalendarBackgroundType BackgroundType
+        if (!EventSuppressor.IsSet(Suppress.Settings))
         {
-            get => (CalendarBackgroundType)GetValue(BackgroundTypeProperty);
-            set => SetValue(BackgroundTypeProperty, value);
+            calendar.Properties.BackgroundType = calendar.BackgroundType;
+            calendar.DoSaveSettings();
         }
+        calendar.BackgroundTypeSelector.SelectedIndex = (int)calendar.BackgroundType;
+        calendar.Refresh();
+    }
 
-        private static void BackgroundType_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
+    private void BackgroundTypeSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        using (new EventSuppressor(Suppress.Selector))
+            BackgroundType = (CalendarBackgroundType)BackgroundTypeSelector.SelectedIndex;
+    }
 
-            if (!EventSuppressor.IsSet(Suppress.Settings))
-            {
-                calendar.Properties.BackgroundType = calendar.BackgroundType;
-                calendar.DoSaveSettings();
-            }
-            calendar.BackgroundTypeSelector.SelectedIndex = (int)calendar.BackgroundType;
-            calendar.Refresh();
-        }
+    #endregion
+    
+    #region Zoom Dependency Properties
+    
+    public static readonly DependencyProperty ZoomProperty =
+        DependencyProperty.Register(
+            nameof(Zoom), 
+            typeof(double), 
+            typeof(Calendar), 
+            new UIPropertyMetadata(100.0, Zoom_Changed, Zoom_Coerce)
+        );
+
+    private static object Zoom_Coerce(DependencyObject d, object baseValue)
+    {
+        if (baseValue is not double zoom) return baseValue;
+        return Math.Max(zoom, 100.0);
+    }
 
-        private void BackgroundTypeSelector_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            using (new EventSuppressor(Suppress.Selector))
-                BackgroundType = (CalendarBackgroundType)BackgroundTypeSelector.SelectedIndex;
-        }
+    public double Zoom
+    {
+        get => (double)GetValue(ZoomProperty);
+        set => SetValue(ZoomProperty, value);
+    }
 
-        #endregion
-        
-        #region Zoom Dependency Properties
-        
-        public static readonly DependencyProperty ZoomProperty =
-            DependencyProperty.Register(
-                nameof(Zoom), 
-                typeof(double), 
-                typeof(Calendar), 
-                new UIPropertyMetadata(100.0, Zoom_Changed, Zoom_Coerce)
-            );
+    private static void Zoom_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
+    {
+        if (d is not Calendar calendar) return;
 
-        private static object Zoom_Coerce(DependencyObject d, object baseValue)
-        {
-            if (baseValue is not double zoom) return baseValue;
-            return Math.Max(zoom, 100.0);
-        }
+        calendar.CalendarControl.Zoom = calendar.Zoom / 100;
+        calendar.ZoomSelector.Text = $"{calendar.Zoom:F0}%";
+    }
 
-        public double Zoom
-        {
-            get => (double)GetValue(ZoomProperty);
-            set => SetValue(ZoomProperty, value);
-        }
+    private void ZoomSelector_Down_Click(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        ZoomOut();
+    }
+    
+    private void ZoomSelector_Up_Click(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        ZoomIn();
+    }
 
-        private static void Zoom_Changed(DependencyObject d, DependencyPropertyChangedEventArgs e)
-        {
-            if (d is not Calendar calendar) return;
+    public void ZoomIn() => Zoom *= 1.125;
+    public void ZoomOut() => Zoom /= 1.125;
+    public void ResetZoom() => Zoom = 100;
 
-            calendar.CalendarControl.Zoom = calendar.Zoom / 100;
-            calendar.ZoomSelector.Text = $"{calendar.Zoom:F0}%";
-        }
+    #endregion
 
-        private void ZoomSelector_Down_Click(object sender, RoutedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            ZoomOut();
-        }
-        
-        private void ZoomSelector_Up_Click(object sender, RoutedEventArgs e)
-        {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            ZoomIn();
-        }
+    #endregion
 
-        public void ZoomIn() => Zoom *= 1.125;
-        public void ZoomOut() => Zoom /= 1.125;
-        public void ResetZoom() => Zoom = 100;
+    #region Event Handlers
 
-        #endregion
+    public event LoadSettings<CalendarSettings>? LoadSettings;
+    
+    public event SaveSettings<CalendarSettings>? SaveSettings;
 
-        #endregion
+    public CalendarConfigurationEvent? ConfigurationChanged;
+    
+    public event CalendarDataMenuEvent? CustomiseContextMenu;
+    
+    public event CalendarDataEvent? SelectionChanged;
 
-        #region Event Handlers
+    public event CalendarDataEvent? ItemCreated;        
+    
+    public event CalendarDataEvent? ItemChanged;
 
-        public event LoadSettings<CalendarSettings>? LoadSettings;
-        
-        public event SaveSettings<CalendarSettings>? SaveSettings;
+    public event CalendarHandledEvent? ItemEditing;
+    
+    #endregion
 
-        public CalendarConfigurationEvent? ConfigurationChanged;
-        
-        public event CalendarDataMenuEvent? CustomiseContextMenu;
-        
-        public event CalendarDataEvent? SelectionChanged;
+    public void SelectEmployee(Guid employeeid) => EmployeeSelector.SelectEmployee(employeeid);
 
-        public event CalendarDataEvent? ItemCreated;        
-        
-        public event CalendarDataEvent? ItemChanged;
+    // Populated as requiew when EmployeeSelector.SelectionChanged is triggered
+    private Employee[] _employees = [];
 
-        public event CalendarHandledEvent? ItemEditing;
-        
-        #endregion
+    // Populated once at startup
+    private StandardLeave[] _standardleaves = [];
+    private LeaveRequest[] _leaverequests = [];
 
-        public void SelectEmployee(Guid employeeid) => EmployeeSelector.SelectEmployee(employeeid);
+    // Populated on each Refresh
+    private TimeSheet[] _timesheets = [];
 
-        // Populated as requiew when EmployeeSelector.SelectionChanged is triggered
-        private Employee[] _employees = [];
+    // Populated on each Refresh
+    private List<Assignment> _assignments = [];
 
-        // Populated once at startup
-        private StandardLeave[] _standardleaves = [];
-        private LeaveRequest[] _leaverequests = [];
+    private MeetingTemplate[]? _meetingTemplates;
 
-        // Populated on each Refresh
-        private TimeSheet[] _timesheets = [];
+    private MeetingTemplate[] MeetingTemplates
+    {
+        get
+        {
+            _meetingTemplates ??= Client.Query(
+                Filter.All<MeetingTemplate>(),
+                MeetingGrid.RequiredTemplateColumns())
+                .ToArray<MeetingTemplate>();
+            return _meetingTemplates;
+        }
+    }
 
-        // Populated on each Refresh
-        private List<Assignment> _assignments = [];
 
-        private ObservableCollection<ICalendarAppointment> _appointments = new();
-        
-        private bool bColumnsLoaded;
-        
-        private AssignmentGrid? ag;
-        private LeaveRequestGrid? lg;
-        private StandardLeaveGrid? slg;
-        private DynamicDataGrid<Meeting>? mg;
-        
-        public bool IsReady { get; set; }
+    private ObservableCollection<ICalendarAppointment> _appointments = new();
+    
+    private bool bColumnsLoaded;
+    
+    private AssignmentGrid? ag;
+    private LeaveRequestGrid? lg;
+    private StandardLeaveGrid? slg;
+    
+    public bool IsReady { get; set; }
 
-        public CalendarSettings Properties { get; set; } = new();
+    public CalendarSettings Properties { get; set; } = new();
 
-        public Calendar()
+    public Calendar()
+    {
+        using (EventSuppressor.All<Suppress>())
         {
-            using (EventSuppressor.All<Suppress>())
-            {
-                InitializeComponent();
-
-                _splitPanel.DataContext = this;
+            InitializeComponent();
 
-                StartHour = 0;
-                EndHour = 24;
-            }
-
-            CalendarControl.GetFillBlockStart = GetFillBlockStart;
-            CalendarControl.GetFillBlockEnd = GetFillBlockEnd;
+            _splitPanel.DataContext = this;
 
-            CalendarControl.RowInterval = TimeIntervalToTimeSpan(TimeInterval);
-            CalendarViewSelector.ItemsSource = new List<KeyValuePair<CalendarViewType, string>>
-            {
-                new(CalendarViewType.Day, "Day"),
-                new(CalendarViewType.WorkWeek, "Work Week"),
-                new(CalendarViewType.Week, "Week"),
-            };
-            CalendarViewSelector.DisplayMemberPath = "Value";
-            CalendarViewSelector.SelectedValuePath = "Key";
+            StartHour = 0;
+            EndHour = 24;
         }
 
-        public virtual void Setup()
-        {
-            using (new EventSuppressor(Suppress.Settings, Suppress.Refresh, Suppress.Events))
-            {
-                Properties = LoadSettings?.Invoke(this) ?? new CalendarSettings();
-                SettingsVisible = Properties.SettingsVisible;
-                SelectedDate = Properties.AlwaysStartOnToday ? DateTime.Today : Properties.Date;
-                StartHour = Properties.StartHour;
-                EndHour = Properties.EndHour;
-                TimeInterval = Properties.TimeInterval;
-                AssignmentType = Properties.AssignmentType;
-                BackgroundType = Properties.BackgroundType;
-                CalendarView = Properties.CalendarView;
-                Zoom = Properties.Zoom;
-                EmployeeSelector.Setup();
-                EmployeeSettings = Properties.EmployeeSelector;
-                EmployeeSelection = Properties.EmployeeSelection;
-                AlwaysTodayBox.IsChecked = Properties.AlwaysStartOnToday;
+        CalendarControl.GetFillBlockStart = GetFillBlockStart;
+        CalendarControl.GetFillBlockEnd = GetFillBlockEnd;
 
-                ReloadColumns();
-            }
-        }
-        
-        public virtual void Shutdown(CancelEventArgs? cancel)
+        CalendarControl.RowInterval = TimeIntervalToTimeSpan(TimeInterval);
+        CalendarViewSelector.ItemsSource = new List<KeyValuePair<CalendarViewType, string>>
         {
-        }
+            new(CalendarViewType.Day, "Day"),
+            new(CalendarViewType.WorkWeek, "Work Week"),
+            new(CalendarViewType.Week, "Week"),
+        };
+        CalendarViewSelector.DisplayMemberPath = "Value";
+        CalendarViewSelector.SelectedValuePath = "Key";
+    }
 
-        private void DoSaveSettings()
-        {
-            SaveSettings?.Invoke(this, Properties);
-        }
-        
-        private bool bFirst = true;
-        
-        public virtual void Refresh()
-        {
-            RefreshData(StartDate, EndDate);
+    public virtual void Setup()
+    {
+        using (new EventSuppressor(Suppress.Settings, Suppress.Refresh, Suppress.Events))
+        {
+            Properties = LoadSettings?.Invoke(this) ?? new CalendarSettings();
+            SettingsVisible = Properties.SettingsVisible;
+            SelectedDate = Properties.AlwaysStartOnToday ? DateTime.Today : Properties.Date;
+            StartHour = Properties.StartHour;
+            EndHour = Properties.EndHour;
+            TimeInterval = Properties.TimeInterval;
+            AssignmentType = Properties.AssignmentType;
+            BackgroundType = Properties.BackgroundType;
+            CalendarView = Properties.CalendarView;
+            Zoom = Properties.Zoom;
+            EmployeeSelector.Setup();
+            EmployeeSettings = Properties.EmployeeSelector;
+            EmployeeSelection = Properties.EmployeeSelection;
+            AlwaysTodayBox.IsChecked = Properties.AlwaysStartOnToday;
+
+            ReloadColumns();
         }
+    }
+    
+    public virtual void Shutdown(CancelEventArgs? cancel)
+    {
+    }
 
-        private bool _refreshing = false;
+    private void DoSaveSettings()
+    {
+        SaveSettings?.Invoke(this, Properties);
+    }
+    
+    private bool bFirst = true;
+    
+    public virtual void Refresh()
+    {
+        RefreshData(StartDate, EndDate);
+    }
 
-        private void RefreshData(DateTime startDate, DateTime endDate)
+    private bool _refreshing = false;
+
+    private void RefreshData(DateTime startDate, DateTime endDate)
+    {
+        if (EventSuppressor.IsSet(Suppress.Refresh))
+            return;
+        if (!_refreshing)
         {
-            if (EventSuppressor.IsSet(Suppress.Refresh))
-                return;
-            if (!_refreshing)
-            {
-                _refreshing = true;
-                Dispatcher.BeginInvoke(() => DoRefreshData(startDate, endDate));
-            }
+            _refreshing = true;
+            Dispatcher.BeginInvoke(() => DoRefreshData(startDate, endDate));
         }
+    }
 
-        private void DoRefreshData(DateTime startDate, DateTime endDate)
+    private void DoRefreshData(DateTime startDate, DateTime endDate)
+    {
+        _refreshing = false;
+        using (new WaitCursor())
         {
-            _refreshing = false;
-            using (new WaitCursor())
-            {
-                if (!bColumnsLoaded)
-                    ReloadColumns();
+            if (!bColumnsLoaded)
+                ReloadColumns();
 
-                var query = new MultiQuery();
+            var query = new MultiQuery();
 
-                var empids = _employees.ToArray(x => x.ID);
-                
-                if (BackgroundType != CalendarBackgroundType.Roster)
-                {
-                    query.Add(
-                        Filter<TimeSheet>.Where(x => x.Employee.ID).InList(empids)
-                            .And(x => x.Date).IsGreaterThanOrEqualTo(startDate)
-                            .And(x => x.Date).IsLessThanOrEqualTo(endDate)
-                            .And(x=>x.LeaveRequest.ID).IsEqualTo(Guid.Empty)
-                            .And(x=>x.StandardLeave.ID).IsEqualTo(Guid.Empty),
-                        TimeSheetModel.Columns
-                    );
-                }
-                
+            var empids = _employees.ToArray(x => x.ID);
+            
+            if (BackgroundType != CalendarBackgroundType.Roster)
+            {
                 query.Add(
-                    Filter<Assignment>.Where(x => x.Employee.ID).InList(empids)
+                    Filter<TimeSheet>.Where(x => x.Employee.ID).InList(empids)
                         .And(x => x.Date).IsGreaterThanOrEqualTo(startDate)
-                        .And(x => x.Date).IsLessThanOrEqualTo(endDate),
-                    AssignmentModel.Columns,
-                    new SortOrder<Assignment>(x => x.Employee.ID).ThenBy(x => x.Date).ThenBy(x => x.Booked.Duration, SortDirection.Descending)
+                        .And(x => x.Date).IsLessThanOrEqualTo(endDate)
+                        .And(x=>x.LeaveRequest.ID).IsEqualTo(Guid.Empty)
+                        .And(x=>x.StandardLeave.ID).IsEqualTo(Guid.Empty),
+                    TimeSheetModel.Columns
                 );
-                
-                query.Add(
-                    Filter<LeaveRequest>
-                        .Where(x => x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected)
-                        .And(x => x.Employee.ID).InList(empids)
-                        .And(x => x.From).IsLessThanOrEqualTo(endDate)
-                        .And(x => x.To).IsGreaterThanOrEqualTo(startDate),
-                    Columns.None<LeaveRequest>()
-                        .Add(x => x.ID)
-                        .Add(x => x.Employee.ID)
-                        .Add(x => x.From)
-                        .Add(x => x.FromTime)
-                        .Add(x => x.To)
-                        .Add(x => x.ToTime)
-                        .Add(x => x.LeaveType.Description)
-                        .Add(x => x.LeaveType.Color)
-                        .Add(x => x.Status)
-                        .Add(x => x.Notes));
-                
-                query.Add(
-                    Filter<StandardLeave>
-                        .Where(x => x.From).IsLessThanOrEqualTo(endDate)
-                        .And(x => x.To).IsGreaterThanOrEqualTo(startDate),
-                    Columns.None<StandardLeave>()
-                        .Add(x => x.ID)
-                        .Add(c => c.ID)
-                        .Add(c => c.LeaveType.Description)
-                        .Add(c => c.Name)
-                        .Add(c => c.LeaveType.Color)
-                        .Add(c => c.From)
-                        .Add(c => c.FromTime)
-                        .Add(c => c.To)
-                        .Add(c => c.ToTime));
-                
-                query.Query();
+            }
+            
+            query.Add(
+                Filter<Assignment>.Where(x => x.Employee.ID).InList(empids)
+                    .And(x => x.Date).IsGreaterThanOrEqualTo(startDate)
+                    .And(x => x.Date).IsLessThanOrEqualTo(endDate),
+                AssignmentModel.Columns,
+                new SortOrder<Assignment>(x => x.Employee.ID).ThenBy(x => x.Date).ThenBy(x => x.Booked.Duration, SortDirection.Descending)
+            );
+            
+            query.Add(
+                Filter<LeaveRequest>
+                    .Where(x => x.Status).IsNotEqualTo(LeaveRequestStatus.Rejected)
+                    .And(x => x.Employee.ID).InList(empids)
+                    .And(x => x.From).IsLessThanOrEqualTo(endDate)
+                    .And(x => x.To).IsGreaterThanOrEqualTo(startDate),
+                Columns.None<LeaveRequest>()
+                    .Add(x => x.ID)
+                    .Add(x => x.Employee.ID)
+                    .Add(x => x.From)
+                    .Add(x => x.FromTime)
+                    .Add(x => x.To)
+                    .Add(x => x.ToTime)
+                    .Add(x => x.LeaveType.Description)
+                    .Add(x => x.LeaveType.Color)
+                    .Add(x => x.Status)
+                    .Add(x => x.Notes));
+            
+            query.Add(
+                Filter<StandardLeave>
+                    .Where(x => x.From).IsLessThanOrEqualTo(endDate)
+                    .And(x => x.To).IsGreaterThanOrEqualTo(startDate),
+                Columns.None<StandardLeave>()
+                    .Add(x => x.ID)
+                    .Add(c => c.ID)
+                    .Add(c => c.LeaveType.Description)
+                    .Add(c => c.Name)
+                    .Add(c => c.LeaveType.Color)
+                    .Add(c => c.From)
+                    .Add(c => c.FromTime)
+                    .Add(c => c.To)
+                    .Add(c => c.ToTime));
+            
+            query.Query();
 
-                _timesheets = (BackgroundType == CalendarBackgroundType.Roster)
-                    ? []
-                    : query.Get<TimeSheet>().ToArray<TimeSheet>();
+            _timesheets = (BackgroundType == CalendarBackgroundType.Roster)
+                ? []
+                : query.Get<TimeSheet>().ToArray<TimeSheet>();
 
-                _leaverequests = query.Get<LeaveRequest>().ToArray<LeaveRequest>();
-                _assignments = query.Get<Assignment>().ToList<Assignment>();
+            _leaverequests = query.Get<LeaveRequest>().ToArray<LeaveRequest>();
+            _assignments = query.Get<Assignment>().ToList<Assignment>();
 
-                _standardleaves = query.Get<StandardLeave>().ToArray<StandardLeave>();
-                
-                LoadBackground();
-
-                _appointments.Clear();
-                LoadStandardLeaves(_appointments);
-                LoadLeaveRequests(_appointments);
-                LoadAssignments(_appointments);
- 
-                try
-                {
-                    CalendarControl.Dates = CoreUtils.Range(startDate, endDate, x => x.AddDays(1));
-                    CalendarControl.ItemsSource = _appointments;
-                }
-                catch (Exception e)
-                {
-                    Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
-                }
+            _standardleaves = query.Get<StandardLeave>().ToArray<StandardLeave>();
+            
+            LoadBackground();
 
-                bFirst = false;
+            _appointments.Clear();
+            LoadStandardLeaves(_appointments);
+            LoadLeaveRequests(_appointments);
+            LoadAssignments(_appointments);
+
+            try
+            {
+                CalendarControl.Dates = CoreUtils.Range(startDate, endDate, x => x.AddDays(1));
+                CalendarControl.ItemsSource = _appointments;
             }
+            catch (Exception e)
+            {
+                Logger.Send(LogType.Error, "", string.Format("*** Unknown Error: {0}\n{1}", e.Message, e.StackTrace));
+            }
+
+            bFirst = false;
         }
+    }
 
-        public EmployeeRosterItem? GetRoster(Guid employeeid, DateTime date)
-        {
-            var employee = _employees.FirstOrDefault(x => x.ID == employeeid);
-            if (employee is null) return null;
+    public EmployeeRosterItem? GetRoster(Guid employeeid, DateTime date)
+    {
+        var employee = _employees.FirstOrDefault(x => x.ID == employeeid);
+        if (employee is null) return null;
 
-            var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employeeid), employee.RosterStart, date);
-            return roster;
-        }
+        var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employeeid), employee.RosterStart, date);
+        return roster;
+    }
 
-        public bool GetActiveWindow(Guid employeeid, DateTime date, ref TimeSpan start, ref TimeSpan finish)
-        {
-            var result = false;
+    public bool GetActiveWindow(Guid employeeid, DateTime date, ref TimeSpan start, ref TimeSpan finish)
+    {
+        var result = false;
 
-            foreach (var assignment in _assignments.Where(a => (a.Employee.ID == employeeid) && (a.Date) == date))
+        foreach (var assignment in _assignments.Where(a => (a.Employee.ID == employeeid) && (a.Date) == date))
+        {
+            result = true;
+            var curstart = AssignmentType switch
             {
-                result = true;
-                var curstart = AssignmentType switch
-                {
-                    CalendarAssignmentType.Booked => assignment.Booked.Start,
-                    CalendarAssignmentType.Actual => assignment.Actual.Start,
-                    _ => Assignment.EffectiveTime(assignment.Actual.Start, assignment.Booked.Start)
-                };
-                
-                var curfinish = AssignmentType switch
-                {
-                    CalendarAssignmentType.Booked => assignment.Booked.Finish,
-                    CalendarAssignmentType.Actual => assignment.Actual.Finish,
-                    _ => Assignment.EffectiveTime(
-                            assignment.Actual.Finish, 
-                            Assignment.EffectiveTime(assignment.Actual.Start, assignment.Booked.Start)
-                            .Add(assignment.Booked.Duration)
-                    )
-                };
-                
-                start = start > curstart ? curstart : start;
-                finish = finish < curfinish ? curfinish : finish;
-            }
+                CalendarAssignmentType.Booked => assignment.Booked.Start,
+                CalendarAssignmentType.Actual => assignment.Actual.Start,
+                _ => Assignment.EffectiveTime(assignment.Actual.Start, assignment.Booked.Start)
+            };
+            
+            var curfinish = AssignmentType switch
+            {
+                CalendarAssignmentType.Booked => assignment.Booked.Finish,
+                CalendarAssignmentType.Actual => assignment.Actual.Finish,
+                _ => Assignment.EffectiveTime(
+                        assignment.Actual.Finish, 
+                        Assignment.EffectiveTime(assignment.Actual.Start, assignment.Booked.Start)
+                        .Add(assignment.Booked.Duration)
+                )
+            };
+            
+            start = start > curstart ? curstart : start;
+            finish = finish < curfinish ? curfinish : finish;
+        }
 
-            if ((BackgroundType == CalendarBackgroundType.Roster) ||
-                ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
+        if ((BackgroundType == CalendarBackgroundType.Roster) ||
+            ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
+        {
+            var employee = _employees.FirstOrDefault(x => x.ID == employeeid);
+            if (employee != null)
             {
-                var employee = _employees.FirstOrDefault(x => x.ID == employeeid);
-                if (employee != null)
+                var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employeeid), employee.RosterStart, date);
+                if (roster != null)
                 {
-                    var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employeeid), employee.RosterStart, date);
-                    if (roster != null)
+                    var blocks = roster.GetBlocks(date, TimeSpan.MinValue, TimeSpan.MaxValue);
+                    foreach (var block in blocks)
                     {
-                        var blocks = roster.GetBlocks(date, TimeSpan.MinValue, TimeSpan.MaxValue);
-                        foreach (var block in blocks)
-                        {
-                            start = start > block.Start ? block.Start : start;
-                            finish = finish < block.Finish ? block.Finish : finish;
-                        }
+                        start = start > block.Start ? block.Start : start;
+                        finish = finish < block.Finish ? block.Finish : finish;
                     }
                 }
             }
-            else
-            {
-                foreach (var timesheet in _timesheets.Where(t => (t.Employee.ID == employeeid) && (t.Date == date)))
-                {
-                    result = true;
-                    var curstart = !timesheet.Approved.IsEmpty()
-                        ? timesheet.ApprovedStart
-                        : timesheet.Start;
-                    var curfinish = !timesheet.Approved.IsEmpty()
-                        ? timesheet.ApprovedFinish
-                        : timesheet.Finish;
-                    start = start > curstart ? curstart : start;
-                    finish = finish < curfinish ? curfinish : finish;                   
-                }                
-            }
-            
-            return result;
         }
-
-        public Assignment[] GetAssignments(Guid employeeid, DateTime date)
+        else
         {
-            return _assignments.Where(a => (a.Employee.ID == employeeid) && (a.Date == date)).ToArray();
+            foreach (var timesheet in _timesheets.Where(t => (t.Employee.ID == employeeid) && (t.Date == date)))
+            {
+                result = true;
+                var curstart = !timesheet.Approved.IsEmpty()
+                    ? timesheet.ApprovedStart
+                    : timesheet.Start;
+                var curfinish = !timesheet.Approved.IsEmpty()
+                    ? timesheet.ApprovedFinish
+                    : timesheet.Finish;
+                start = start > curstart ? curstart : start;
+                finish = finish < curfinish ? curfinish : finish;                   
+            }                
         }
         
-        private void LoadBackground()
+        return result;
+    }
+
+    public Assignment[] GetAssignments(Guid employeeid, DateTime date)
+    {
+        return _assignments.Where(a => (a.Employee.ID == employeeid) && (a.Date == date)).ToArray();
+    }
+    
+    private void LoadBackground()
+    {
+        var regions = new ObservableCollection<CalendarRegion>();
+        foreach (var employee in _employees)
         {
-            var regions = new ObservableCollection<CalendarRegion>();
-            foreach (var employee in _employees)
+            for (var date = StartDate; date < EndDate; date = date.AddDays(1))
             {
-                for (var date = StartDate; date < EndDate; date = date.AddDays(1))
+                if ((BackgroundType == CalendarBackgroundType.Roster) ||
+                    ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
                 {
-                    if ((BackgroundType == CalendarBackgroundType.Roster) ||
-                        ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
-                    {
-                        var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
-                        if (roster != null)
-                        {
-                            var blocks = roster.GetBlocks(date, TimeSpan.FromSeconds(0), TimeSpan.FromDays(1));
-                            foreach (var block in blocks)
-                            {
-                                regions.Add(new CalendarRegion
-                                {
-                                    Date = date,
-                                    Column = employee,
-                                    Start = block.Start,
-                                    End = block.Finish,
-                                    Background = Colors.Yellow.ToBrush(0.3)
-                                });
-                            }
-                        }
-                    }
-                    else
+                    var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
+                    if (roster != null)
                     {
-                        foreach (var timesheet in _timesheets.Where(t => (t.Employee.ID == employee.ID) && (t.Date == date)))
+                        var blocks = roster.GetBlocks(date, TimeSpan.FromSeconds(0), TimeSpan.FromDays(1));
+                        foreach (var block in blocks)
                         {
-                            var start = !timesheet.Approved.IsEmpty()
-                                ? timesheet.ApprovedStart
-                                : timesheet.Start;
-                            var finish = !timesheet.Approved.IsEmpty()
-                                ? timesheet.ApprovedFinish
-                                : timesheet.Finish;
-                            if(finish == default)
-                            {
-                                finish = TimeSpan.FromHours(24);
-                            }
                             regions.Add(new CalendarRegion
                             {
                                 Date = date,
                                 Column = employee,
-                                Start = start,
-                                End = finish,
-                                Background = (!timesheet.Approved.IsEmpty() ? Colors.LightGreen : Colors.LightSalmon).ToBrush(0.4),
+                                Start = block.Start,
+                                End = block.Finish,
+                                Background = Colors.Yellow.ToBrush(0.3)
                             });
-                        } 
+                        }
                     }
                 }
-            }
-
-            CalendarControl.Regions = regions;
-        }
-        
-        private void LoadStandardLeaves(IList<ICalendarAppointment> appointments)
-        {
-            for (var date = StartDate; date < EndDate; date = date.AddDays(1))
-            {
-                var leaves = _standardleaves.Where(x => 
-                    (x.From <= date)
-                    && (x.To.Add(x.ToTime) > date)
-                ).ToArray();
-                foreach (var leave in leaves)
+                else
                 {
-                    foreach (var employee in _employees)
+                    foreach (var timesheet in _timesheets.Where(t => (t.Employee.ID == employee.ID) && (t.Date == date)))
                     {
-                        var start = (date.Date == leave.From.Date) ? leave.FromTime : TimeSpan.FromSeconds(0);
-                        var finish = (date.Date == leave.To.Date) ? leave.ToTime : TimeSpan.FromDays(1).Subtract(TimeSpan.FromSeconds(1));
-
-                        var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
-                        if (roster != null)
+                        var start = !timesheet.Approved.IsEmpty()
+                            ? timesheet.ApprovedStart
+                            : timesheet.Start;
+                        var finish = !timesheet.Approved.IsEmpty()
+                            ? timesheet.ApprovedFinish
+                            : timesheet.Finish;
+                        if(finish == default)
                         {
-                            var blocks = roster.GetBlocks(date, start, finish);
-                            foreach (var block in blocks)
-                            {
-                                var appt = new StandardLeaveAppointment(leave, employee, block);
-                                appointments.Add(appt);
-                            }
+                            finish = TimeSpan.FromHours(24);
                         }
-                    }
+                        regions.Add(new CalendarRegion
+                        {
+                            Date = date,
+                            Column = employee,
+                            Start = start,
+                            End = finish,
+                            Background = (!timesheet.Approved.IsEmpty() ? Colors.LightGreen : Colors.LightSalmon).ToBrush(0.4),
+                        });
+                    } 
                 }
             }
         }
 
-        private void LoadLeaveRequests(IList<ICalendarAppointment> appointments)
+        CalendarControl.Regions = regions;
+    }
+    
+    private void LoadStandardLeaves(IList<ICalendarAppointment> appointments)
+    {
+        for (var date = StartDate; date < EndDate; date = date.AddDays(1))
         {
-            for (var date = StartDate; date < EndDate; date = date.AddDays(1))
+            var leaves = _standardleaves.Where(x => 
+                (x.From <= date)
+                && (x.To.Add(x.ToTime) > date)
+            ).ToArray();
+            foreach (var leave in leaves)
             {
-                var ids = _employees.ToArray(x => x.ID);
-
-                var leaves = _leaverequests.Where(x => 
-                    (x.From <= date) 
-                    && (x.To.Add(x.ToTime) > date) 
-                    && ids.Contains(x.Employee.ID) 
-                ).ToArray();
-
-                foreach (var leave in leaves)
+                foreach (var employee in _employees)
                 {
-                    var employee = _employees.FirstOrDefault(x => x.ID == leave.Employee.ID);
-                    if (employee is null) return;
-                    
+                    var start = (date.Date == leave.From.Date) ? leave.FromTime : TimeSpan.FromSeconds(0);
+                    var finish = (date.Date == leave.To.Date) ? leave.ToTime : TimeSpan.FromDays(1).Subtract(TimeSpan.FromSeconds(1));
+
                     var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
                     if (roster != null)
                     {
-                        var start = (date.Date == leave.From.Date) ? leave.FromTime : TimeSpan.FromSeconds(0);
-                        var finish = (date.Date == leave.To.Date) ? leave.ToTime : TimeSpan.FromDays(1).Subtract(TimeSpan.FromSeconds(1));
                         var blocks = roster.GetBlocks(date, start, finish);
-                        foreach(var block in blocks)
+                        foreach (var block in blocks)
                         {
-                            appointments.Add(new LeaveRequestAppointment(leave, employee, block));
+                            var appt = new StandardLeaveAppointment(leave, employee, block);
+                            appointments.Add(appt);
                         }
                     }
                 }
             }
         }
+    }
 
-        private HashSet<Assignment> _savingAssignments = new();
-        
-        private AssignmentAppointment? LoadAssignment(Assignment assignment, IList<ICalendarAppointment> appointments)
-        {
-            var employee = _employees.FirstOrDefault(x => x.ID == assignment.Employee.ID);
-            if (employee is null) return null;
-
-            var model = new AssignmentAppointment(assignment, employee, AssignmentType);
-            model.OnUpdate += () =>
-            {
-                if (_savingAssignments.Add(assignment))
-                {
-                    Dispatcher.BeginInvoke(() =>
-                    {
-                        _savingAssignments.Remove(assignment);
-                        Client.SaveAsync(assignment, "Edited by user").LogIfFail();
-                    });
-                }
-            };
-            model.EmployeeChanged += (o, e) =>
-            {
-                model.Employee = _employees.FirstOrDefault(x => x.ID == assignment.Employee.ID);
-            };
-            appointments.Add(model);
-            return model;
-        }
-
-        private void LoadAssignments(IList<ICalendarAppointment> appointments)
-        {
-            foreach (var assignment in _assignments)
-                LoadAssignment(assignment, appointments);
-        }
-        
-        public DataModel DataModel(Selection selection)
-        {
-            var ids = _assignments.Select(x => x.ID).ToArray();
-            return new AutoDataModel<Assignment>(Filter<Assignment>.Where(x => x.ID).InList(ids));
-        }
-
-        private static T CheckGrid<T>([NotNull] ref T? grid) where T : new()
-        {
-            grid ??= new T();
-            return grid;
-        }
-
-        private void ReloadColumns()
-        {
-            CalendarControl.Columns = _employees.OrderBy(x => x.Name);
-            bColumnsLoaded = true;
-        }
-
-        #region Block
-
-        private (TimeSpan Start, TimeSpan End)? GetFillBlock(DateTime date, object? column, TimeSpan time)
+    private void LoadLeaveRequests(IList<ICalendarAppointment> appointments)
+    {
+        for (var date = StartDate; date < EndDate; date = date.AddDays(1))
         {
-            if (column is not Employee employee) return null;
-
-            if ((BackgroundType == CalendarBackgroundType.Roster) ||
-                ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
-            {
-                var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
-                if (roster is null) return null;
+            var ids = _employees.ToArray(x => x.ID);
 
-                var blocks = roster.GetBlocks(date, TimeSpan.Zero, TimeSpan.FromDays(1));
-                var block = blocks.FirstOrDefault(x => x.Start <= time && time <= x.Finish);
-                if (block is null) return null;
+            var leaves = _leaverequests.Where(x => 
+                (x.From <= date) 
+                && (x.To.Add(x.ToTime) > date) 
+                && ids.Contains(x.Employee.ID) 
+            ).ToArray();
 
-                return (block.Start, block.Finish);
-            }
-            else
+            foreach (var leave in leaves)
             {
-                foreach (var timesheet in _timesheets.Where(t => (t.Employee.ID == employee.ID) && (t.Date == date)))
+                var employee = _employees.FirstOrDefault(x => x.ID == leave.Employee.ID);
+                if (employee is null) return;
+                
+                var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
+                if (roster != null)
                 {
-                    var start = !timesheet.Approved.IsEmpty()
-                        ? timesheet.ApprovedStart
-                        : timesheet.Start;
-                    var finish = !timesheet.Approved.IsEmpty()
-                        ? timesheet.ApprovedFinish
-                        : timesheet.Finish;
-                    if(finish == default)
+                    var start = (date.Date == leave.From.Date) ? leave.FromTime : TimeSpan.FromSeconds(0);
+                    var finish = (date.Date == leave.To.Date) ? leave.ToTime : TimeSpan.FromDays(1).Subtract(TimeSpan.FromSeconds(1));
+                    var blocks = roster.GetBlocks(date, start, finish);
+                    foreach(var block in blocks)
                     {
-                        finish = TimeSpan.FromHours(24);
+                        appointments.Add(new LeaveRequestAppointment(leave, employee, block));
                     }
-                    if(start <= time && time <= finish)
-                    {
-                        return (start, finish);
-                    }
-                } 
-
-                return null;
+                }
             }
         }
+    }
 
-        private TimeSpan? GetFillBlockStart(DateTime date, object? column, TimeSpan time)
-        {
-            var block = GetFillBlock(date, column, time);
-            return block?.Start;
-        }
+    private HashSet<Assignment> _savingAssignments = new();
+    
+    private AssignmentAppointment? LoadAssignment(Assignment assignment, IList<ICalendarAppointment> appointments)
+    {
+        var employee = _employees.FirstOrDefault(x => x.ID == assignment.Employee.ID);
+        if (employee is null) return null;
 
-        private TimeSpan? GetFillBlockEnd(DateTime date, object? column, TimeSpan time)
+        var model = new AssignmentAppointment(assignment, employee, AssignmentType);
+        model.OnUpdate += () =>
         {
-            var block = GetFillBlock(date, column, time);
-            return block?.End;
-        }
-
-        private void Calendar_BlockHeld(object sender, CalendarBlockEventArgs e)
+            if (_savingAssignments.Add(assignment))
+            {
+                Dispatcher.BeginInvoke(() =>
+                {
+                    _savingAssignments.Remove(assignment);
+                    Client.SaveAsync(assignment, "Edited by user").LogIfFail();
+                });
+            }
+        };
+        model.EmployeeChanged += (o, e) =>
         {
-            OpenContextMenu(sender, e, false);
-        }
+            model.Employee = _employees.FirstOrDefault(x => x.ID == assignment.Employee.ID);
+        };
+        appointments.Add(model);
+        return model;
+    }
+
+    private void LoadAssignments(IList<ICalendarAppointment> appointments)
+    {
+        foreach (var assignment in _assignments)
+            LoadAssignment(assignment, appointments);
+    }
+    
+    public DataModel DataModel(Selection selection)
+    {
+        var ids = _assignments.Select(x => x.ID).ToArray();
+        return new AutoDataModel<Assignment>(Filter<Assignment>.Where(x => x.ID).InList(ids));
+    }
+
+    private static T CheckGrid<T>([NotNull] ref T? grid) where T : new()
+    {
+        grid ??= new T();
+        return grid;
+    }
+
+    private void ReloadColumns()
+    {
+        CalendarControl.Columns = _employees.OrderBy(x => x.Name);
+        bColumnsLoaded = true;
+    }
+
+    #region Block
+
+    private (TimeSpan Start, TimeSpan End)? GetFillBlock(DateTime date, object? column, TimeSpan time)
+    {
+        if (column is not Employee employee) return null;
 
-        public enum ContextMenuItems
+        if ((BackgroundType == CalendarBackgroundType.Roster) ||
+            ((BackgroundType == CalendarBackgroundType.Automatic) && (date >= DateTime.Today)))
         {
-            Create,
-            Fill
-        }
+            var roster = RosterUtils.GetRoster(EmployeeSelector.GetRoster(employee.ID), employee.RosterStart, date);
+            if (roster is null) return null;
 
-        public CalendarTimeSlot FillSlot(CalendarBlockEventArgs e, CalendarTimeSlot slot)
+            var blocks = roster.GetBlocks(date, TimeSpan.Zero, TimeSpan.FromDays(1));
+            var block = blocks.FirstOrDefault(x => x.Start <= time && time <= x.Finish);
+            if (block is null) return null;
+
+            return (block.Start, block.Finish);
+        }
+        else
         {
-            if(CalendarControl.GetEmptySpace(e.Point, out var start, out var end))
+            foreach (var timesheet in _timesheets.Where(t => (t.Employee.ID == employee.ID) && (t.Date == date)))
             {
-                if(start is null || end is null)
+                var start = !timesheet.Approved.IsEmpty()
+                    ? timesheet.ApprovedStart
+                    : timesheet.Start;
+                var finish = !timesheet.Approved.IsEmpty()
+                    ? timesheet.ApprovedFinish
+                    : timesheet.Finish;
+                if(finish == default)
                 {
-                    var block = GetFillBlock(e.Date, e.Column, CalendarControl.GetTime(e.Point));
-                    return new(slot.EmployeeID, e.Date, start ?? block?.Start ?? e.Start, end ?? block?.End ?? e.End);
+                    finish = TimeSpan.FromHours(24);
                 }
-                else
+                if(start <= time && time <= finish)
                 {
-                    return new(slot.EmployeeID, e.Date, start.Value, end.Value);
+                    return (start, finish);
                 }
+            } 
+
+            return null;
+        }
+    }
+
+    private TimeSpan? GetFillBlockStart(DateTime date, object? column, TimeSpan time)
+    {
+        var block = GetFillBlock(date, column, time);
+        return block?.Start;
+    }
+
+    private TimeSpan? GetFillBlockEnd(DateTime date, object? column, TimeSpan time)
+    {
+        var block = GetFillBlock(date, column, time);
+        return block?.End;
+    }
+
+    private void Calendar_BlockHeld(object sender, CalendarBlockEventArgs e)
+    {
+        OpenContextMenu(sender, e, false);
+    }
+
+    public enum ContextMenuItems
+    {
+        Create,
+        Fill
+    }
+
+    public CalendarTimeSlot FillSlot(CalendarBlockEventArgs e, CalendarTimeSlot slot)
+    {
+        if(CalendarControl.GetEmptySpace(e.Point, out var start, out var end))
+        {
+            if(start is null || end is null)
+            {
+                var block = GetFillBlock(e.Date, e.Column, CalendarControl.GetTime(e.Point));
+                return new(slot.EmployeeID, e.Date, start ?? block?.Start ?? e.Start, end ?? block?.End ?? e.End);
             }
             else
             {
-                return slot;
+                return new(slot.EmployeeID, e.Date, start.Value, end.Value);
             }
         }
-        private void Calendar_BlockRightClicked(object sender, CalendarBlockEventArgs e)
+        else
         {
-            OpenContextMenu(sender, e, true);
+            return slot;
         }
+    }
+    private void Calendar_BlockRightClicked(object sender, CalendarBlockEventArgs e)
+    {
+        OpenContextMenu(sender, e, true);
+    }
 
-        private void OpenContextMenu(object sender, CalendarBlockEventArgs e, bool allowFill)
+    private void OpenContextMenu(object sender, CalendarBlockEventArgs e, bool allowFill)
+    {
+        object? value;
+        if(e.Value is AssignmentAppointment appointment)
         {
-            object? value;
-            if(e.Value is AssignmentAppointment appointment)
+            if (appointment.Model.Meeting.Link.ID != Guid.Empty)
             {
-                if (appointment.Model.Meeting.Link.ID != Guid.Empty)
-                {
-                    e.Menu.AddItem("Edit Meeting", null, appointment.Model, EditMeeting);
-                }
-                else
+                e.Menu.AddItem("Edit Meeting", null, appointment.Model, EditMeeting);
+            }
+            else
+            {
+                e.Menu.AddItem("Edit Assignment", null, appointment.Model, EditAssignment);
+                e.Menu.AddSeparator();
+                e.Menu.AddItem("Copy Assignment", null, appointment.Model, CopyAssignment);
+                e.Menu.AddSeparator();
+                e.Menu.AddItem("Fill Available Time", null, () =>
                 {
-                    e.Menu.AddItem("Edit Assignment", null, appointment.Model, EditAssignment);
-                    e.Menu.AddSeparator();
-                    e.Menu.AddItem("Copy Assignment", null, appointment.Model, CopyAssignment);
-                    e.Menu.AddSeparator();
-                    e.Menu.AddItem("Fill Available Time", null, () =>
+                    if(CalendarControl.GetEmptySpace(e.Point, out var start, out var end, time: e.Start, exclude: [appointment]))
                     {
-                        if(CalendarControl.GetEmptySpace(e.Point, out var start, out var end, time: e.Start, exclude: [appointment]))
+                        var time = AssignmentType switch
                         {
-                            var time = AssignmentType switch
-                            {
-                                CalendarAssignmentType.Automatic or CalendarAssignmentType.Actual => appointment.Model.Actual,
-                                CalendarAssignmentType.Booked => appointment.Model.Booked,
-                                _ => throw new InvalidEnumException<CalendarAssignmentType>(AssignmentType)
-                            };
-                            if(start is null || end is null)
-                            {
-                                var block = GetFillBlock(e.Date, e.Column, e.Start);
-                                time.Start = start ?? block?.Start ?? time.Start;
-                                time.Finish = end ?? block?.End ?? time.Finish;
-                            }
-                            else
-                            {
-                                time.Start = start.Value;
-                                time.Finish = end.Value;
-                            }
-                            Client.Save(appointment.Model, "Adjusted to fill time");
+                            CalendarAssignmentType.Automatic or CalendarAssignmentType.Actual => appointment.Model.Actual,
+                            CalendarAssignmentType.Booked => appointment.Model.Booked,
+                            _ => throw new InvalidEnumException<CalendarAssignmentType>(AssignmentType)
+                        };
+                        if(start is null || end is null)
+                        {
+                            var block = GetFillBlock(e.Date, e.Column, e.Start);
+                            time.Start = start ?? block?.Start ?? time.Start;
+                            time.Finish = end ?? block?.End ?? time.Finish;
                         }
-                    });
-                }
-                e.Menu.AddSeparatorIfNeeded();
-            
-                CreateDigitalFormsMenu(e.Menu, appointment);
-
-                e.Menu.AddSeparatorIfNeeded();
-                if (appointment.Model.Meeting.Link.ID != Guid.Empty)
-                {
-                    e.Menu.AddItem("Delete Meeting", null, appointment.Model, DeleteMeeting);
-                }
-                else
-                {
-                    e.Menu.AddItem("Delete Assignment", null, appointment.Model, DeleteAssignment);
-                }
-
-                value = appointment.Model;
+                        else
+                        {
+                            time.Start = start.Value;
+                            time.Finish = end.Value;
+                        }
+                        Client.Save(appointment.Model, "Adjusted to fill time");
+                    }
+                });
             }
-            else if(e.Value is LeaveRequestAppointment leaveAppointment)
-            {
-                if (Security.CanView<LeaveRequest>())
-                {
-                    e.Menu.AddItem(
-                        Security.CanEdit<LeaveRequest>() ? "Edit Leave" : "View Leave",
-                        null,
-                        leaveAppointment.Model,
-                        EditLeave);
-                }
+            e.Menu.AddSeparatorIfNeeded();
+        
+            CreateDigitalFormsMenu(e.Menu, appointment);
 
-                value = leaveAppointment.Model;
+            e.Menu.AddSeparatorIfNeeded();
+            if (appointment.Model.Meeting.Link.ID != Guid.Empty)
+            {
+                e.Menu.AddItem("Delete Meeting", null, appointment.Model, DeleteMeeting);
             }
-            else if(e.Value is StandardLeaveAppointment standardLeaveAppointment)
+            else
             {
-                if (Security.CanView<StandardLeave>())
-                {
-                    e.Menu.AddItem(
-                        Security.CanEdit<StandardLeave>() ? "Edit Standard Leave" : "View Standard Leave",
-                        null,
-                        standardLeaveAppointment.Model,
-                        EditStandardLeave);
-                }
+                e.Menu.AddItem("Delete Assignment", null, appointment.Model, DeleteAssignment);
+            }
 
-                value = standardLeaveAppointment.Model;
+            value = appointment.Model;
+        }
+        else if(e.Value is LeaveRequestAppointment leaveAppointment)
+        {
+            if (Security.CanView<LeaveRequest>())
+            {
+                e.Menu.AddItem(
+                    Security.CanEdit<LeaveRequest>() ? "Edit Leave" : "View Leave",
+                    null,
+                    leaveAppointment.Model,
+                    EditLeave);
             }
-            else if (e.Value is null)
+
+            value = leaveAppointment.Model;
+        }
+        else if(e.Value is StandardLeaveAppointment standardLeaveAppointment)
+        {
+            if (Security.CanView<StandardLeave>())
             {
-                if (e.Column is not Employee employee) return;
+                e.Menu.AddItem(
+                    Security.CanEdit<StandardLeave>() ? "Edit Standard Leave" : "View Standard Leave",
+                    null,
+                    standardLeaveAppointment.Model,
+                    EditStandardLeave);
+            }
 
-                var slot = new CalendarTimeSlot(employee.ID, e.Date, e.Start, e.End);
+            value = standardLeaveAppointment.Model;
+        }
+        else if (e.Value is null)
+        {
+            if (e.Column is not Employee employee) return;
 
-                var createmenu = e.Menu.AddItem("Create...", null, null)
-                    .WithName($"Menu_{nameof(ContextMenuItems.Create)}");
-                createmenu.AddItem("New Assignment", null, slot, slot => CreateAssignment(slot));
-                // createmenu.AddItem("New Meeting", null, slot, CreateMeeting);
+            var slot = new CalendarTimeSlot(employee.ID, e.Date, e.Start, e.End);
 
-                if (allowFill)
+            var createmenu = e.Menu.AddItem("Create...", null, null)
+                .WithName($"Menu_{nameof(ContextMenuItems.Create)}");
+            createmenu.AddItem("New Assignment", null, slot, slot => CreateAssignment(slot));
+
+            void AddNewMeetingItem(MenuItem item, Func<CalendarTimeSlot> getSlot)
+            {
+                if(MeetingTemplates.Length == 0)
                 {
-                    var fillMenu = e.Menu.AddItem("Fill...", null, null)
-                        .WithName($"Menu_{nameof(ContextMenuItems.Fill)}");
-                    fillMenu.AddItem("New Assignment", null, () => CreateAssignment(FillSlot(e, slot)));
-                    // fillMenu.AddItem("New Meeting", null, () => CreateMeeting(FillSlot(e, slot)));
+                    item.AddItem("New Meeting", null, () => CreateMeeting(getSlot(), null));
                 }
-
-                if (_copiedmodel != null)
+                else
                 {
-                    e.Menu.AddSeparator();
-                    e.Menu.AddItem("Paste Assignment", null, slot, slot => PasteAssignment(slot, _copiedmodel));
+                    var newMeetingItem = item.AddItem("New Meeting", null, null);
+                    newMeetingItem.AddItem("Blank Meeting", null, () => CreateMeeting(getSlot(), null));
+                    newMeetingItem.AddSeparator();
+                    foreach(var template in MeetingTemplates)
+                    {
+                        newMeetingItem.AddItem(template.Title, null, () => CreateMeeting(getSlot(), template));
+                    }
                 }
-
-                value = slot;
             }
-            else
+
+            AddNewMeetingItem(createmenu, () => slot);
+
+            if (allowFill)
             {
-                value = null;
+                var fillMenu = e.Menu.AddItem("Fill...", null, null)
+                    .WithName($"Menu_{nameof(ContextMenuItems.Fill)}");
+                fillMenu.AddItem("New Assignment", null, () => CreateAssignment(FillSlot(e, slot)));
+                AddNewMeetingItem(fillMenu, () => FillSlot(e, slot));
             }
 
-            e.Menu.AddSeparatorIfNeeded();
-
-            e.Menu.AddItem("Zoom In", null, ZoomIn);
-            e.Menu.AddItem("Zoom Out", null, ZoomOut, enabled: Zoom > 100);
-            e.Menu.AddItem("Reset Zoom", null, ResetZoom);
+            if (_copiedmodel != null)
+            {
+                e.Menu.AddSeparator();
+                e.Menu.AddItem("Paste Assignment", null, slot, slot => PasteAssignment(slot, _copiedmodel));
+            }
 
-            CustomiseContextMenu?.Invoke(e.Menu, new CalendarDataMenuEventArgs(value, e));
+            value = slot;
         }
-        
-        private static void CreateDigitalFormsMenu(ContextMenu menu, AssignmentAppointment appointment)
+        else
         {
-            var digitalForms = menu.AddItem("Digital Forms", null, null);
-            DynamicGridUtils.PopulateFormMenu<AssignmentForm, Assignment, AssignmentLink>(
-                digitalForms,
-                appointment.Model.ID,
-                () => new Client<Assignment>().Load(Filter<Assignment>.Where(x => x.ID).IsEqualTo(appointment.Model.ID)).First(),
-                false);
+            value = null;
         }
 
-        public void CreateMeeting(CalendarTimeSlot slot)
-        {
-            var meeting = new Meeting
-            {
-                Date = slot.Date
-            };
+        e.Menu.AddSeparatorIfNeeded();
 
-            meeting.Time.Start = slot.Start;
-            meeting.Time.Finish = slot.End;
-            
-            ItemCreated?.Invoke(this, new CalendarDataEventArgs(meeting));
-            
-            var args = new CalendarHandledEventArgs<Meeting>(meeting);
-            ItemEditing?.Invoke(this, args);
-            
-            if (args.Status == CalendarHandledStatus.Cancel)
-                return;
-            if (args.Status == CalendarHandledStatus.Handled)
-            {
-                Refresh();
-                return;
-            }
-            CheckGrid(ref mg);
-            var items = new[] { meeting };
-            bool bOK = mg.EditItems(
-                items, 
-                (type) =>
-                {
-                    if (type == typeof(Assignment))
-                        return LoadMeetingEmployees(slot.EmployeeID);
-                    else if (type == typeof(MeetingItem))
-                        return LoadMeetingItems();
-                    return null;
-                }, 
-                true
-            );
-            if (bOK)
-                Refresh();
-        }
+        e.Menu.AddItem("Zoom In", null, ZoomIn);
+        e.Menu.AddItem("Zoom Out", null, ZoomOut, enabled: Zoom > 100);
+        e.Menu.AddItem("Reset Zoom", null, ResetZoom);
 
-        private static CoreTable LoadMeetingEmployees(Guid employeeid)
-        {
-            var result = new CoreTable();
-            result.LoadColumns(typeof(Assignment));
-            var assignment = new Assignment();
-            LookupFactory.DoLookup<Assignment, Employee, EmployeeLink>(assignment, x => x.Employee, employeeid);
-            result.LoadRows([assignment]);
-            return result;
-        }
+        CustomiseContextMenu?.Invoke(e.Menu, new CalendarDataMenuEventArgs(value, e));
+    }
+    
+    private static void CreateDigitalFormsMenu(ContextMenu menu, AssignmentAppointment appointment)
+    {
+        var digitalForms = menu.AddItem("Digital Forms", null, null);
+        DynamicGridUtils.PopulateFormMenu<AssignmentForm, Assignment, AssignmentLink>(
+            digitalForms,
+            appointment.Model.ID,
+            () => new Client<Assignment>().Load(Filter<Assignment>.Where(x => x.ID).IsEqualTo(appointment.Model.ID)).First(),
+            false);
+    }
 
-        private static CoreTable LoadMeetingItems()
+    public void CreateMeeting(CalendarTimeSlot slot, MeetingTemplate? template)
+    {
+        var meeting = new Meeting
         {
-            var result = new CoreTable();
-            result.LoadColumns(typeof(MeetingItem));
-            return result;
-        }
+            Date = slot.Date
+        };
+
+        meeting.Time.Start = slot.Start;
+        meeting.Time.Finish = slot.End;
 
-        private void EditMeeting(Assignment model)
+        if(template is not null)
         {
-            CheckGrid(ref mg);
-            
-            if (DynamicGridUtils.EditEntity<Meeting>(model.Meeting.Link.ID, out var meeting))
-            {
-                ItemChanged?.Invoke(this, new CalendarDataEventArgs(meeting));
-                Refresh();
-            }
+            meeting.Title = template.Title;
+            meeting.Description = template.Description;
+            meeting.Activity.CopyFrom(template.Activity);
         }
         
-        private void DeleteMeeting(Assignment model)
+        ItemCreated?.Invoke(this, new CalendarDataEventArgs(meeting));
+        
+        var args = new CalendarHandledEventArgs<Meeting>(meeting);
+        ItemEditing?.Invoke(this, args);
+        
+        if (args.Status == CalendarHandledStatus.Cancel)
+            return;
+        if (args.Status == CalendarHandledStatus.Handled)
         {
-            if (!MessageWindow.ShowYesNo("Are you sure you wish to delete this meeting?", "Confirm Delete"))
-                return;
-            
-            var meeting = new Meeting { ID = model.Meeting.Link.ID };
-            Client.Delete(meeting, "Meeting Deleted from Scheduler");
-            ItemChanged?.Invoke(this, new CalendarDataEventArgs(meeting));
             Refresh();
-            SelectionChanged?.Invoke(this, new CalendarDataEventArgs(null));
+            return;
         }
-        
-        public Assignment? CreateAssignment(CalendarTimeSlot slot)
+        if (DynamicGridUtils.EditEntity(meeting))
         {
-            var ass = new Assignment
-            {
-                Date = slot.Date
-            };
-
-            ass.Booked.Start = slot.Start;
-            ass.Booked.Finish = slot.End;
-            if ((AssignmentType == CalendarAssignmentType.Actual) || ((AssignmentType == CalendarAssignmentType.Automatic) && (ass.Date <= DateTime.Today)))
+            var makeAssignment = true;
+            if(template is not null)
             {
-                ass.Actual.Start = ass.Booked.Start;
-                ass.Actual.Finish = ass.Booked.Finish;
+                MeetingGrid.InitialiseMeetingChildrenFromTemplate(meeting, template, out var assignments);
+                makeAssignment = !assignments.Any(x => x.Employee.ID == slot.EmployeeID);
             }
-            
-            ass.Employee.ID = slot.EmployeeID;
 
-            ItemCreated?.Invoke(this, new CalendarDataEventArgs(ass));
-            
-            var args = new CalendarHandledEventArgs<Assignment>(ass);
-            ItemEditing?.Invoke(this, args);
-            if (args.Status == CalendarHandledStatus.Cancel)
-                return null;
-            
-            if ((args.Status == CalendarHandledStatus.Handled) || CheckGrid(ref ag).EditItems([ass]))
+            if (makeAssignment)
             {
-                _assignments.Add(ass);
-                CalendarControl.SelectItem(LoadAssignment(ass, _appointments));
-                _copiedmodel = null;
+                var assignment = new Assignment();
+                assignment.Employee.ID = slot.EmployeeID;
+                assignment.Meeting.Link.CopyFrom(meeting);
+                assignment.Meeting.IsAdmin = true;
+                assignment.Date = meeting.Date;
+                assignment.Booked.Start = meeting.Time.Start;
+                assignment.Booked.Finish = meeting.Time.Finish;
+                assignment.Activity.CopyFrom(meeting.Activity);
+                assignment.Title = meeting.Title;
+                assignment.Description = meeting.Description;
+                Client.Save(assignment, "Created Assignment from meeting.");
             }
 
-            return ass;
-
+            Refresh();
         }
+    }
 
-        private void EditAssignment(Assignment model)
+    private void EditMeeting(Assignment model)
+    {
+        if (DynamicGridUtils.EditEntity<Meeting>(model.Meeting.Link.ID, out var meeting))
         {
-            var grid = CheckGrid(ref ag);
-            Client.EnsureColumns(model, grid.LoadEditorColumns());
-
-            if (DynamicGridUtils.EditEntity<Assignment>(model))
-            {
-                ItemChanged?.Invoke(this, new CalendarDataEventArgs(model));
-                // Refresh();
-            }
+            ItemChanged?.Invoke(this, new CalendarDataEventArgs(meeting));
+            Refresh();
         }
-
-        private void DeleteAssignment(Assignment model)
+    }
+    
+    private void DeleteMeeting(Assignment model)
+    {
+        if (!MessageWindow.ShowYesNo("Are you sure you wish to delete this meeting?", "Confirm Delete"))
+            return;
+        
+        var meeting = new Meeting { ID = model.Meeting.Link.ID };
+        Client.Delete(meeting, "Meeting Deleted from Scheduler");
+        ItemChanged?.Invoke(this, new CalendarDataEventArgs(meeting));
+        Refresh();
+        SelectionChanged?.Invoke(this, new CalendarDataEventArgs(null));
+    }
+    
+    public Assignment? CreateAssignment(CalendarTimeSlot slot)
+    {
+        var ass = new Assignment
         {
-            if (!MessageWindow.ShowYesNo("Are you sure you wish to delete this assignment?", "Confirm Delete"))
-                return;
-            
-            var ass = new Assignment { ID = model.ID };
-            Client.Delete(ass, "Assignment Deleted from Scheduler");
-            ItemChanged?.Invoke(this, new CalendarDataEventArgs(ass));
-            Refresh();
-            SelectionChanged?.Invoke(this, new CalendarDataEventArgs(null));
+            Date = slot.Date
+        };
 
+        ass.Booked.Start = slot.Start;
+        ass.Booked.Finish = slot.End;
+        if ((AssignmentType == CalendarAssignmentType.Actual) || ((AssignmentType == CalendarAssignmentType.Automatic) && (ass.Date <= DateTime.Today)))
+        {
+            ass.Actual.Start = ass.Booked.Start;
+            ass.Actual.Finish = ass.Booked.Finish;
         }
         
-        private Assignment? _copiedmodel;
+        ass.Employee.ID = slot.EmployeeID;
 
-        private void CopyAssignment(Assignment model)
+        ItemCreated?.Invoke(this, new CalendarDataEventArgs(ass));
+        
+        var args = new CalendarHandledEventArgs<Assignment>(ass);
+        ItemEditing?.Invoke(this, args);
+        if (args.Status == CalendarHandledStatus.Cancel)
+            return null;
+        
+        if ((args.Status == CalendarHandledStatus.Handled) || CheckGrid(ref ag).EditItems([ass]))
         {
-            _copiedmodel = model;
+            _assignments.Add(ass);
+            CalendarControl.SelectItem(LoadAssignment(ass, _appointments));
+            _copiedmodel = null;
         }
 
-        private Assignment PasteAssignment(CalendarTimeSlot slot, Assignment copied)
+        return ass;
+
+    }
+
+    private void EditAssignment(Assignment model)
+    {
+        var grid = CheckGrid(ref ag);
+        Client.EnsureColumns(model, grid.LoadEditorColumns());
+
+        if (DynamicGridUtils.EditEntity<Assignment>(model))
         {
-            var ass = copied.Clone();
+            ItemChanged?.Invoke(this, new CalendarDataEventArgs(model));
+            // Refresh();
+        }
+    }
 
-            ass.Date = slot.Date;
-            ass.ID = Guid.Empty;
-            ass.Number = 0;
-            ass.CommitChanges();
+    private void DeleteAssignment(Assignment model)
+    {
+        if (!MessageWindow.ShowYesNo("Are you sure you wish to delete this assignment?", "Confirm Delete"))
+            return;
+        
+        var ass = new Assignment { ID = model.ID };
+        Client.Delete(ass, "Assignment Deleted from Scheduler");
+        ItemChanged?.Invoke(this, new CalendarDataEventArgs(ass));
+        Refresh();
+        SelectionChanged?.Invoke(this, new CalendarDataEventArgs(null));
 
-            ass.Booked.Start = slot.Start;
-            ass.Booked.Finish = slot.End;
-            if ((AssignmentType == CalendarAssignmentType.Actual) || ((AssignmentType == CalendarAssignmentType.Automatic) && (ass.Date <= DateTime.Today)))
-            {
-                ass.Actual.Start = ass.Booked.Start;
-                ass.Actual.Finish = ass.Booked.Finish;
-            }
-            
-            ass.Employee.ID = slot.EmployeeID;
-            ass.Employee.Clear();
+    }
+    
+    private Assignment? _copiedmodel;
 
-            Client.Save(ass, "");
+    private void CopyAssignment(Assignment model)
+    {
+        _copiedmodel = model;
+    }
 
-            _assignments.Add(ass);
-            CalendarControl.SelectItem(LoadAssignment(ass, _appointments));
-            _copiedmodel = null;
-            return ass;
+    private Assignment PasteAssignment(CalendarTimeSlot slot, Assignment copied)
+    {
+        var ass = copied.Clone();
 
-        }
+        ass.Date = slot.Date;
+        ass.ID = Guid.Empty;
+        ass.Number = 0;
+        ass.CommitChanges();
 
-        private void EditLeave(LeaveRequest model)
+        ass.Booked.Start = slot.Start;
+        ass.Booked.Finish = slot.End;
+        if ((AssignmentType == CalendarAssignmentType.Actual) || ((AssignmentType == CalendarAssignmentType.Automatic) && (ass.Date <= DateTime.Today)))
         {
-            var grid = CheckGrid(ref lg);
-            Client.EnsureColumns(model, grid.LoadEditorColumns());
-
-            if (DynamicGridUtils.EditEntity(model))
-            {
-                ItemChanged?.Invoke(this, new CalendarDataEventArgs(model));
-                Refresh();
-            }
+            ass.Actual.Start = ass.Booked.Start;
+            ass.Actual.Finish = ass.Booked.Finish;
         }
+        
+        ass.Employee.ID = slot.EmployeeID;
+        ass.Employee.Clear();
 
-        private void EditStandardLeave(StandardLeave model)
-        {
-            var grid = CheckGrid(ref slg);
-            Client.EnsureColumns(model, grid.LoadEditorColumns());
+        Client.Save(ass, "");
 
-            if (DynamicGridUtils.EditEntity(model))
-            {
-                ItemChanged?.Invoke(this, new CalendarDataEventArgs(model));
-                Refresh();
-            }
-        }
+        _assignments.Add(ass);
+        CalendarControl.SelectItem(LoadAssignment(ass, _appointments));
+        _copiedmodel = null;
+        return ass;
+
+    }
+
+    private void EditLeave(LeaveRequest model)
+    {
+        var grid = CheckGrid(ref lg);
+        Client.EnsureColumns(model, grid.LoadEditorColumns());
 
-        private void Calendar_BlockClicked(object sender, CalendarBlockEventArgs e)
+        if (DynamicGridUtils.EditEntity(model))
         {
-            if(e.Value is AssignmentAppointment appointment)
-            {
-                var args = new CalendarDataEventArgs(appointment.Model);
-                SelectionChanged?.Invoke(this, args);
-            }
-            else
-            {
-                SelectionChanged?.Invoke(this, new CalendarDataEventArgs(null));
-            }
+            ItemChanged?.Invoke(this, new CalendarDataEventArgs(model));
+            Refresh();
         }
+    }
 
-        #endregion
-
-        #region Layout
+    private void EditStandardLeave(StandardLeave model)
+    {
+        var grid = CheckGrid(ref slg);
+        Client.EnsureColumns(model, grid.LoadEditorColumns());
 
-        private void _settingsButton_OnClick(object sender, RoutedEventArgs e)
+        if (DynamicGridUtils.EditEntity(model))
         {
-            _splitPanel.View = DynamicSplitPanelView.Master;
+            ItemChanged?.Invoke(this, new CalendarDataEventArgs(model));
+            Refresh();
         }
+    }
 
-        private void _splitPanel_OnOnChanged(object sender, DynamicSplitPanelSettings e)
+    private void Calendar_BlockClicked(object sender, CalendarBlockEventArgs e)
+    {
+        if(e.Value is AssignmentAppointment appointment)
+        {
+            var args = new CalendarDataEventArgs(appointment.Model);
+            SelectionChanged?.Invoke(this, args);
+        }
+        else
         {
-            if (EventSuppressor.IsSet(Suppress.Events))
-                return;
-            if (e.View == DynamicSplitPanelView.Combined && SettingsVisible != CalendarSettingsVisibility.Visible)
-                SettingsVisible = CalendarSettingsVisibility.Visible;
-            else if (e.View == DynamicSplitPanelView.Master && SettingsVisible == CalendarSettingsVisibility.Visible)
-                SettingsVisible = CalendarSettingsVisibility.Hidden;
+            SelectionChanged?.Invoke(this, new CalendarDataEventArgs(null));
         }
+    }
 
-        #endregion
+    #endregion
 
-        private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
-        {
-            if (sender is not TextBlock block || block.Tag is not Employee employee) return;
+    #region Layout
 
-            var display = employee.Name;
-            var comps = employee.Name.Split(' ');
+    private void _settingsButton_OnClick(object sender, RoutedEventArgs e)
+    {
+        _splitPanel.View = DynamicSplitPanelView.Master;
+    }
 
-            if(block.ActualWidth < 75)
-            {
-                display = (comps[0].Length > 0 ? comps[0][..1] : "")
-                    + (comps.Length > 1 ? comps.Skip(1).First()[..1].ToUpper() : "");
-            }
-            else if(block.ActualWidth < 150)
-            {
-                display = comps.First() + " " + (comps.Length > 1 ? comps.Skip(1).First()[..1].ToUpper() : "");
-            }
-            block.Text = display;
-        }
+    private void _splitPanel_OnOnChanged(object sender, DynamicSplitPanelSettings e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events))
+            return;
+        if (e.View == DynamicSplitPanelView.Combined && SettingsVisible != CalendarSettingsVisibility.Visible)
+            SettingsVisible = CalendarSettingsVisibility.Visible;
+        else if (e.View == DynamicSplitPanelView.Master && SettingsVisible == CalendarSettingsVisibility.Visible)
+            SettingsVisible = CalendarSettingsVisibility.Hidden;
+    }
+
+    #endregion
+
+    private void TextBlock_SizeChanged(object sender, SizeChangedEventArgs e)
+    {
+        if (sender is not TextBlock block || block.Tag is not Employee employee) return;
 
-        #region Date Selection
+        var display = employee.Name;
+        var comps = employee.Name.Split(' ');
 
-        private void Left_Click(object sender, RoutedEventArgs e)
+        if(block.ActualWidth < 75)
         {
-            SelectedDate = SelectedDate.AddDays(CalendarView switch
-            {
-                CalendarViewType.Day => -1,
-                CalendarViewType.WorkWeek or CalendarViewType.Week => -7,
-                _ => throw new InvalidEnumException<CalendarViewType>(CalendarView)
-            });
+            display = (comps[0].Length > 0 ? comps[0][..1] : "")
+                + (comps.Length > 1 ? comps.Skip(1).First()[..1].ToUpper() : "");
         }
-
-        private void Right_Click(object sender, RoutedEventArgs e)
+        else if(block.ActualWidth < 150)
         {
-            SelectedDate = SelectedDate.AddDays(CalendarView switch
-            {
-                CalendarViewType.Day => 1,
-                CalendarViewType.WorkWeek or CalendarViewType.Week => 7,
-                _ => throw new InvalidEnumException<CalendarViewType>(CalendarView)
-            });
+            display = comps.First() + " " + (comps.Length > 1 ? comps.Skip(1).First()[..1].ToUpper() : "");
         }
+        block.Text = display;
+    }
 
-        private void Today_Click(object sender, RoutedEventArgs e)
+    #region Date Selection
+
+    private void Left_Click(object sender, RoutedEventArgs e)
+    {
+        SelectedDate = SelectedDate.AddDays(CalendarView switch
         {
-            SelectedDate = DateTime.Today;
-        }
+            CalendarViewType.Day => -1,
+            CalendarViewType.WorkWeek or CalendarViewType.Week => -7,
+            _ => throw new InvalidEnumException<CalendarViewType>(CalendarView)
+        });
+    }
 
-        private void AlwaysTodayBox_Checked(object sender, RoutedEventArgs e)
+    private void Right_Click(object sender, RoutedEventArgs e)
+    {
+        SelectedDate = SelectedDate.AddDays(CalendarView switch
         {
-            if (EventSuppressor.IsSet(Suppress.Events)) return;
+            CalendarViewType.Day => 1,
+            CalendarViewType.WorkWeek or CalendarViewType.Week => 7,
+            _ => throw new InvalidEnumException<CalendarViewType>(CalendarView)
+        });
+    }
 
-            Properties.AlwaysStartOnToday = AlwaysTodayBox.IsChecked == true;
-            DoSaveSettings();
-        }
+    private void Today_Click(object sender, RoutedEventArgs e)
+    {
+        SelectedDate = DateTime.Today;
+    }
+
+    private void AlwaysTodayBox_Checked(object sender, RoutedEventArgs e)
+    {
+        if (EventSuppressor.IsSet(Suppress.Events)) return;
 
-        #endregion
+        Properties.AlwaysStartOnToday = AlwaysTodayBox.IsChecked == true;
+        DoSaveSettings();
     }
+
+    #endregion
 }

+ 70 - 64
prs.desktop/Panels/Meeting/MeetingGrid.cs

@@ -26,6 +26,7 @@ public class MeetingGrid : DynamicDataGrid<Meeting>
     public static Columns<MeetingTemplate> RequiredTemplateColumns()
     {
         return Columns.None<MeetingTemplate>()
+            .Add(x => x.ID)
             .Add(x => x.Title)
             .Add(x => x.Description)
             .Add(x => x.Activity.ID);
@@ -42,6 +43,74 @@ public class MeetingGrid : DynamicDataGrid<Meeting>
         options.SelectColumns = true;
     }
 
+    public static void InitialiseMeetingChildrenFromTemplate(Meeting meeting, MeetingTemplate template,
+        out List<Assignment> assignments)
+    {
+        var data = new MultiQuery()
+            .Add(
+                Filter<MeetingTemplateItem>.Where(x => x.Template.ID).IsEqualTo(template.ID),
+                Columns.None<MeetingTemplateItem>()
+                    .Add(x => x.ID)
+                    .Add(x => x.Parent.ID)
+                    .Add(x => x.Title)
+                    .Add(x => x.Notes))
+            .Add(
+                Filter<MeetingTemplateAttendee>.Where(x => x.Template.ID).IsEqualTo(template.ID),
+                Columns.None<MeetingTemplateAttendee>()
+                    .Add(x => x.Employee.ID)
+                    .Add(x => x.IsAdmin))
+            .Query();
+
+        var meetingItems = new List<MeetingItem>();
+
+        var dictionary = new Dictionary<MeetingItem, MeetingTemplateItem>();
+        var reverseDictionary = new Dictionary<MeetingTemplateItem, MeetingItem>();
+        var templateDictionary = new Dictionary<Guid, MeetingTemplateItem>();
+        foreach(var templateItem in data.GetObjects<MeetingTemplateItem>())
+        {
+            var meetingItem = new MeetingItem();
+            meetingItem.Meeting.CopyFrom(meeting);
+            meetingItem.Title = templateItem.Title;
+            meetingItem.Notes = templateItem.Notes;
+            meetingItems.Add(meetingItem);
+
+            dictionary.Add(meetingItem, templateItem);
+            reverseDictionary.Add(templateItem, meetingItem);
+            templateDictionary.Add(templateItem.ID, templateItem);
+        }
+
+        Client.Save(meetingItems, "Created Meeting Items from Template");
+
+        foreach(var meetingItem in meetingItems)
+        {
+            var templateItem = dictionary[meetingItem];
+            if(templateItem.Parent.ID != Guid.Empty
+                && templateDictionary.TryGetValue(templateItem.Parent.ID, out var parent))
+            {
+                meetingItem.Parent.CopyFrom(reverseDictionary[parent]);
+            }
+        }
+
+        Client.Save(meetingItems, "Linked Meeting Item Parents");
+
+        assignments = new List<Assignment>();
+        foreach(var attendee in data.GetObjects<MeetingTemplateAttendee>())
+        {
+            var assignment = new Assignment();
+            assignment.Employee.CopyFrom(attendee.Employee);
+            assignment.Meeting.Link.CopyFrom(meeting);
+            assignment.Meeting.IsAdmin = attendee.IsAdmin;
+            assignment.Date = meeting.Date;
+            assignment.Booked.Start = meeting.Time.Start;
+            assignment.Booked.Finish = meeting.Time.Finish;
+            assignment.Activity.CopyFrom(meeting.Activity);
+            assignment.Title = meeting.Title;
+            assignment.Description = meeting.Description;
+            assignments.Add(assignment);
+        }
+        Client.Save(assignments, "Created Meeting Assignments from Template");
+    }
+
     protected override void DoAdd(bool openEditorOnDirectEdit = false)
     {
         if(Templates.Count > 0)
@@ -63,70 +132,7 @@ public class MeetingGrid : DynamicDataGrid<Meeting>
 
                     if (EditItems([meeting]))
                     {
-                        var data = new MultiQuery()
-                            .Add(
-                                Filter<MeetingTemplateItem>.Where(x => x.Template.ID).IsEqualTo(template.ID),
-                                Columns.None<MeetingTemplateItem>()
-                                    .Add(x => x.ID)
-                                    .Add(x => x.Parent.ID)
-                                    .Add(x => x.Title)
-                                    .Add(x => x.Notes))
-                            .Add(
-                                Filter<MeetingTemplateAttendee>.Where(x => x.Template.ID).IsEqualTo(template.ID),
-                                Columns.None<MeetingTemplateAttendee>()
-                                    .Add(x => x.Employee.ID)
-                                    .Add(x => x.IsAdmin))
-                            .Query();
-
-                        var meetingItems = new List<MeetingItem>();
-
-                        var dictionary = new Dictionary<MeetingItem, MeetingTemplateItem>();
-                        var reverseDictionary = new Dictionary<MeetingTemplateItem, MeetingItem>();
-                        var templateDictionary = new Dictionary<Guid, MeetingTemplateItem>();
-                        foreach(var templateItem in data.GetObjects<MeetingTemplateItem>())
-                        {
-                            var meetingItem = new MeetingItem();
-                            meetingItem.Meeting.CopyFrom(meeting);
-                            meetingItem.Title = templateItem.Title;
-                            meetingItem.Notes = templateItem.Notes;
-                            meetingItems.Add(meetingItem);
-
-                            dictionary.Add(meetingItem, templateItem);
-                            reverseDictionary.Add(templateItem, meetingItem);
-                            templateDictionary.Add(templateItem.ID, templateItem);
-                        }
-
-                        Client.Save(meetingItems, "Created Meeting Items from Template");
-
-                        foreach(var meetingItem in meetingItems)
-                        {
-                            var templateItem = dictionary[meetingItem];
-                            if(templateItem.Parent.ID != Guid.Empty
-                                && templateDictionary.TryGetValue(templateItem.Parent.ID, out var parent))
-                            {
-                                meetingItem.Parent.CopyFrom(reverseDictionary[parent]);
-                            }
-                        }
-
-                        Client.Save(meetingItems, "Linked Meeting Item Parents");
-
-                        var assignments = new List<Assignment>();
-                        foreach(var attendee in data.GetObjects<MeetingTemplateAttendee>())
-                        {
-                            var assignment = new Assignment();
-                            assignment.Employee.CopyFrom(attendee.Employee);
-                            assignment.Meeting.Link.CopyFrom(meeting);
-                            assignment.Meeting.IsAdmin = attendee.IsAdmin;
-                            assignment.Date = meeting.Date;
-                            assignment.Booked.Start = meeting.Time.Start;
-                            assignment.Booked.Finish = meeting.Time.Finish;
-                            assignment.Activity.CopyFrom(meeting.Activity);
-                            assignment.Title = meeting.Title;
-                            assignment.Description = meeting.Description;
-                            assignments.Add(assignment);
-                        }
-                        Client.Save(assignments, "Created Meeting Assignments from Template");
-
+                        InitialiseMeetingChildrenFromTemplate(meeting, template, out var _assignments);
                         AddNewRow(meeting);
                     }
                 });

+ 15 - 1
prs.desktop/Panels/Meeting/Template/MeetingTemplateAttendeeGrid.cs

@@ -7,6 +7,7 @@ using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Threading.Tasks;
+using System.Windows;
 using System.Windows.Media.Imaging;
 
 namespace PRSDesktop.Panels.Meeting.Template;
@@ -19,7 +20,20 @@ public class MeetingTemplateAttendeeGrid : DynamicManyToManyGrid<MeetingTemplate
     {
         base.Init();
 
-        ActionColumns.Add(new DynamicTickColumn<MeetingTemplateAttendee, bool>(x => x.IsAdmin, tick, tick, null, Tick_Click));
+        ActionColumns.Add(new DynamicTickColumn<MeetingTemplateAttendee, bool>(x => x.IsAdmin, tick, tick, null, Tick_Click)
+        {
+            ToolTip = IsAdmin_ToolTip
+        });
+    }
+
+    private FrameworkElement? IsAdmin_ToolTip(DynamicActionColumn column, CoreRow? row)
+    {
+        if (row is null) return null;
+
+        var item = LoadItem(row);
+        return item.IsAdmin
+            ? column.TextToolTip("This employee will be an administrator of the meeting.")
+            : column.TextToolTip("This employee will not be an administrator of the meeting.");
     }
 
     private bool Tick_Click(CoreRow? row)