From 234eacaecf778f904178527838c97cbb908c8a20 Mon Sep 17 00:00:00 2001 From: Meik Date: Fri, 20 Feb 2026 14:55:35 +0100 Subject: [PATCH] Fix ESC handling in ticket completion dropdowns --- .../UserControls/ComboBoxPageable.xaml.cs | 107 +- .../HierarchicalSelectionControl.xaml.cs | 867 +-- .../Ticket/CloseCaseDialogWithTicket.xaml.cs | 5646 +++++++++-------- .../TicketCompletion/TicketCompletion.xaml.cs | 291 +- 4 files changed, 3489 insertions(+), 3422 deletions(-) diff --git a/FasdDesktopUi/Basics/UserControls/ComboBoxPageable.xaml.cs b/FasdDesktopUi/Basics/UserControls/ComboBoxPageable.xaml.cs index 41df5fb..e547e4d 100644 --- a/FasdDesktopUi/Basics/UserControls/ComboBoxPageable.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/ComboBoxPageable.xaml.cs @@ -1,7 +1,7 @@ using C4IT.FASD.Base; -using C4IT.MultiLanguage; -using FasdDesktopUi.Basics.Helper; -using FasdDesktopUi.Basics.Models; +using C4IT.MultiLanguage; +using FasdDesktopUi.Basics.Helper; +using FasdDesktopUi.Basics.Models; using System; using System.Collections.Generic; using System.Collections.ObjectModel; @@ -125,25 +125,25 @@ namespace FasdDesktopUi.Basics.UserControls } - public static readonly DependencyProperty SearchDataChangedProperty = - DependencyProperty.Register("SearchDataChanged", typeof(EventHandler), typeof(ComboBoxPageable), new PropertyMetadata(null)); - - #endregion - - #region RestoreParentScrollFocusOnDropDownClose - - public bool RestoreParentScrollFocusOnDropDownClose - { - get { return (bool)GetValue(RestoreParentScrollFocusOnDropDownCloseProperty); } - set { SetValue(RestoreParentScrollFocusOnDropDownCloseProperty, value); } - } - - public static readonly DependencyProperty RestoreParentScrollFocusOnDropDownCloseProperty = - DependencyProperty.Register("RestoreParentScrollFocusOnDropDownClose", typeof(bool), typeof(ComboBoxPageable), new PropertyMetadata(false)); - - #endregion - - #region ItemData + public static readonly DependencyProperty SearchDataChangedProperty = + DependencyProperty.Register("SearchDataChanged", typeof(EventHandler), typeof(ComboBoxPageable), new PropertyMetadata(null)); + + #endregion + + #region RestoreParentScrollFocusOnDropDownClose + + public bool RestoreParentScrollFocusOnDropDownClose + { + get { return (bool)GetValue(RestoreParentScrollFocusOnDropDownCloseProperty); } + set { SetValue(RestoreParentScrollFocusOnDropDownCloseProperty, value); } + } + + public static readonly DependencyProperty RestoreParentScrollFocusOnDropDownCloseProperty = + DependencyProperty.Register("RestoreParentScrollFocusOnDropDownClose", typeof(bool), typeof(ComboBoxPageable), new PropertyMetadata(false)); + + #endregion + + #region ItemData public ObservableCollection> ItemData { @@ -222,6 +222,15 @@ namespace FasdDesktopUi.Basics.UserControls return null; } + public bool CloseDropDownIfOpen() + { + if (ComboBoxControl?.IsDropDownOpen != true) + return false; + + ComboBoxControl.IsDropDownOpen = false; + return true; + } + #region Paging Events #region PageBack @@ -316,33 +325,33 @@ namespace FasdDesktopUi.Basics.UserControls } } - private void ComboBoxControl_DropDownClosed(object sender, EventArgs e) - { - timer.Stop(); - cFocusInvoker.InvokeLostFocus(this, e); - - if (RestoreParentScrollFocusOnDropDownClose) - { - _ = Dispatcher.BeginInvoke((Action)(() => - { - try - { - var parentScrollViewer = cUiElementHelper.GetFirstParentOfType(this); - Keyboard.ClearFocus(); - - if (parentScrollViewer != null) - { - parentScrollViewer.Focus(); - Keyboard.Focus(parentScrollViewer); - } - } - catch (Exception exception) - { - LogException(exception); - } - }), System.Windows.Threading.DispatcherPriority.Input); - } - } + private void ComboBoxControl_DropDownClosed(object sender, EventArgs e) + { + timer.Stop(); + cFocusInvoker.InvokeLostFocus(this, e); + + if (RestoreParentScrollFocusOnDropDownClose) + { + _ = Dispatcher.BeginInvoke((Action)(() => + { + try + { + var parentScrollViewer = cUiElementHelper.GetFirstParentOfType(this); + Keyboard.ClearFocus(); + + if (parentScrollViewer != null) + { + parentScrollViewer.Focus(); + Keyboard.Focus(parentScrollViewer); + } + } + catch (Exception exception) + { + LogException(exception); + } + }), System.Windows.Threading.DispatcherPriority.Input); + } + } private void ComboBoxControl_DropDownOpened(object sender, EventArgs e) { diff --git a/FasdDesktopUi/Basics/UserControls/HierarchicalSelectionControl.xaml.cs b/FasdDesktopUi/Basics/UserControls/HierarchicalSelectionControl.xaml.cs index 48b5d8c..eb6b4a1 100644 --- a/FasdDesktopUi/Basics/UserControls/HierarchicalSelectionControl.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/HierarchicalSelectionControl.xaml.cs @@ -1,429 +1,438 @@ -using FasdDesktopUi.Basics.Models; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Threading; - -namespace FasdDesktopUi.Basics.UserControls -{ - public partial class HierarchicalSelectionControl : UserControl - { - private readonly ObservableCollection visibleItems = new ObservableCollection(); - private readonly Dictionary itemLookup = new Dictionary(); - private readonly DispatcherTimer searchDelayTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) }; - private string lastSearchText = string.Empty; - private bool suppressTreeSelectionChanged; - - private TextBox searchTextBox; - private TreeView treeViewControl; - private ScrollViewer itemsScrollViewer; - - public ObservableCollection VisibleItems => visibleItems; - - public event EventHandler DropDownOpened; - public event EventHandler DropDownClosed; - - public HierarchicalSelectionControl() - { - InitializeComponent(); - searchDelayTimer.Tick += SearchDelayTimer_Tick; - } - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - EnsureTemplateParts(); - if (treeViewControl != null) - treeViewControl.ItemsSource = VisibleItems; - } - - #region DependencyProperties - - public ObservableCollection ItemsSource - { - get => (ObservableCollection)GetValue(ItemsSourceProperty); - set => SetValue(ItemsSourceProperty, value); - } - - public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( - nameof(ItemsSource), - typeof(ObservableCollection), - typeof(HierarchicalSelectionControl), - new PropertyMetadata(null, OnItemsSourceChanged)); - - private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is HierarchicalSelectionControl control) - { - control.RebuildLookup(); - control.ApplyFilter(control.lastSearchText); - } - } - - public HierarchicalSelectionItem SelectedItem - { - get => (HierarchicalSelectionItem)GetValue(SelectedItemProperty); - set => SetValue(SelectedItemProperty, value); - } - - public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( - nameof(SelectedItem), - typeof(HierarchicalSelectionItem), - typeof(HierarchicalSelectionControl), - new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemChanged)); - - private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is HierarchicalSelectionControl control) - { - control.TryExpandToSelectedItem(); - control.SyncTreeSelectionWithSelectedItem(bringIntoView: false); - } - } - - public Brush ComboBoxBackground - { - get => (Brush)GetValue(ComboBoxBackgroundProperty); - set => SetValue(ComboBoxBackgroundProperty, value); - } - - public static readonly DependencyProperty ComboBoxBackgroundProperty = - DependencyProperty.Register(nameof(ComboBoxBackground), typeof(Brush), typeof(HierarchicalSelectionControl), new PropertyMetadata(Brushes.Transparent)); - - public string SearchPlaceholderText - { - get => (string)GetValue(SearchPlaceholderTextProperty); - set => SetValue(SearchPlaceholderTextProperty, value); - } - - public static readonly DependencyProperty SearchPlaceholderTextProperty = - DependencyProperty.Register(nameof(SearchPlaceholderText), typeof(string), typeof(HierarchicalSelectionControl), new PropertyMetadata(string.Empty)); - - #endregion - - #region UI Event Handling - - private void ComboBoxControl_DropDownOpened(object sender, EventArgs e) - { - EnsureTemplateParts(); - searchTextBox?.Focus(); - searchTextBox?.SelectAll(); - suppressTreeSelectionChanged = false; - SyncTreeSelectionWithSelectedItem(bringIntoView: true); - DropDownOpened?.Invoke(this, e); - } - - private void ComboBoxControl_DropDownClosed(object sender, EventArgs e) - { - searchDelayTimer.Stop(); - suppressTreeSelectionChanged = false; - DropDownClosed?.Invoke(this, e); - } - - private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) - { - searchDelayTimer.Stop(); - searchDelayTimer.Start(); - } - - private void SearchDelayTimer_Tick(object sender, EventArgs e) - { - searchDelayTimer.Stop(); - lastSearchText = searchTextBox?.Text ?? string.Empty; - ApplyFilter(lastSearchText); - } - - private void TreeViewControl_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) - { - if (suppressTreeSelectionChanged) - return; - - if (e.NewValue is HierarchicalSelectionItem selected) - { - var original = ResolveOriginalItem(selected); - if (original != null && !Equals(SelectedItem, original)) - { - SelectedItem = original; - } - - suppressTreeSelectionChanged = true; - ComboBoxControl.IsDropDownOpen = false; - } - } - - #endregion - - #region Data Preparation and Filtering - - private HierarchicalSelectionItem ResolveOriginalItem(HierarchicalSelectionItem item) - { - if (item == null) - return null; - - if (!string.IsNullOrWhiteSpace(item.Id) && itemLookup.TryGetValue(item.Id, out var original)) - return original; - - return null; - } - - private void RebuildLookup() - { - itemLookup.Clear(); - - if (ItemsSource == null) - return; - - foreach (var entry in ItemsSource.SelectMany(item => item.SelfAndDescendants())) - { - if (string.IsNullOrWhiteSpace(entry.Id)) - continue; - - itemLookup[entry.Id] = entry; - } - } - - private void ApplyFilter(string searchText) - { - visibleItems.Clear(); - - if (ItemsSource == null) - return; - - if (string.IsNullOrWhiteSpace(searchText)) - { - foreach (var item in ItemsSource) - { - item.SetExpandedRecursive(false); - visibleItems.Add(item); - } - - TryExpandToSelectedItem(); - SyncTreeSelectionWithSelectedItem(bringIntoView: false); - return; - } - - var comparison = StringComparison.CurrentCultureIgnoreCase; - - foreach (var root in ItemsSource) - { - var clone = root.CloneBranch(node => - node.FullPath?.IndexOf(searchText, comparison) >= 0 || - node.DisplayName?.IndexOf(searchText, comparison) >= 0); - - if (clone == null) - continue; - - clone.SetExpandedRecursive(true); - visibleItems.Add(clone); - } - - // If the selected item is part of current results, keep it visually selected. - SyncTreeSelectionWithSelectedItem(bringIntoView: false); - } - - private void TryExpandToSelectedItem() - { - if (SelectedItem == null || string.IsNullOrWhiteSpace(SelectedItem.Id)) - return; - - if (!string.IsNullOrWhiteSpace(lastSearchText)) - return; - - var chain = SelectedItem; - while (chain != null) - { - chain.IsExpanded = true; - chain = chain.Parent; - } - } - - #endregion - - #region Tree Selection Sync - - private void SyncTreeSelectionWithSelectedItem(bool bringIntoView) - { - if (SelectedItem == null || string.IsNullOrWhiteSpace(SelectedItem.Id)) - return; - - EnsureTemplateParts(); - if (treeViewControl == null) - return; - - // Wait for popup/template layout to finish so item containers are generated. - Dispatcher.BeginInvoke(new Action(() => - { - var target = FindVisibleItemById(VisibleItems, SelectedItem.Id); - if (target == null) - return; - - var ancestor = target.Parent; - while (ancestor != null) - { - ancestor.IsExpanded = true; - ancestor = ancestor.Parent; - } - - treeViewControl.UpdateLayout(); - var targetContainer = GetTreeViewItemContainer(treeViewControl, target); - if (targetContainer == null) - return; - - suppressTreeSelectionChanged = true; - try - { - targetContainer.IsSelected = true; - if (bringIntoView) - targetContainer.BringIntoView(); - } - finally - { - suppressTreeSelectionChanged = false; - } - }), DispatcherPriority.Loaded); - } - - private static HierarchicalSelectionItem FindVisibleItemById(IEnumerable items, string id) - { - if (items == null || string.IsNullOrWhiteSpace(id)) - return null; - - foreach (var item in items) - { - if (item == null) - continue; - - if (string.Equals(item.Id, id, StringComparison.OrdinalIgnoreCase)) - return item; - - var childMatch = FindVisibleItemById(item.Children, id); - if (childMatch != null) - return childMatch; - } - - return null; - } - - private static TreeViewItem GetTreeViewItemContainer(ItemsControl root, object targetItem) - { - if (root == null || targetItem == null) - return null; - - var directContainer = root.ItemContainerGenerator.ContainerFromItem(targetItem) as TreeViewItem; - if (directContainer != null) - return directContainer; - - foreach (var child in root.Items) - { - var childContainer = root.ItemContainerGenerator.ContainerFromItem(child) as TreeViewItem; - if (childContainer == null) - continue; - - childContainer.UpdateLayout(); - var result = GetTreeViewItemContainer(childContainer, targetItem); - if (result != null) - return result; - } - - return null; - } - - #endregion - - #region Template and Scroll Handling - - private void EnsureTemplateParts() - { - if (treeViewControl == null) - { - treeViewControl = ComboBoxControl.Template.FindName("PART_TreeView", ComboBoxControl) as TreeView; - if (treeViewControl != null) - { - treeViewControl.SelectedItemChanged += TreeViewControl_SelectedItemChanged; - treeViewControl.ItemsSource = VisibleItems; - } - } - - if (searchTextBox == null) - { - searchTextBox = ComboBoxControl.Template.FindName("PART_SearchTextBox", ComboBoxControl) as TextBox; - if (searchTextBox != null) - searchTextBox.TextChanged += SearchTextBox_TextChanged; - } - - if (itemsScrollViewer == null) - { - itemsScrollViewer = ComboBoxControl.Template.FindName("PART_ItemsScrollViewer", ComboBoxControl) as ScrollViewer; - } - } - - private void ItemsScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) - { - var scroller = itemsScrollViewer ?? sender as ScrollViewer; - if (scroller == null || scroller.ScrollableHeight <= 0) - return; - - var lines = SystemParameters.WheelScrollLines; - if (lines < 0) - { - if (e.Delta < 0) - scroller.PageDown(); - else - scroller.PageUp(); - e.Handled = true; - return; - } - - if (lines == 0) - { - scroller.ScrollToVerticalOffset(scroller.VerticalOffset - e.Delta); - e.Handled = true; - return; - } - - var direction = e.Delta < 0 ? 1 : -1; - var stepCount = Math.Max(1, Math.Abs(e.Delta) / 120) * lines; - for (var i = 0; i < stepCount; i++) - { - if (direction > 0) - scroller.LineDown(); - else - scroller.LineUp(); - } - - e.Handled = true; - } - - #endregion - - #region Keyboard - - protected override void OnPreviewKeyDown(KeyEventArgs e) - { - base.OnPreviewKeyDown(e); - - if (!IsEnabled) - return; - - if (!ComboBoxControl.IsDropDownOpen && (e.Key == Key.Enter || e.Key == Key.Down || e.Key == Key.Space)) - { - ComboBoxControl.IsDropDownOpen = true; - e.Handled = true; - return; - } - - if (ComboBoxControl.IsDropDownOpen && e.Key == Key.Escape) - { - ComboBoxControl.IsDropDownOpen = false; - e.Handled = true; - } - } - - #endregion - } -} +using FasdDesktopUi.Basics.Models; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Threading; + +namespace FasdDesktopUi.Basics.UserControls +{ + public partial class HierarchicalSelectionControl : UserControl + { + private readonly ObservableCollection visibleItems = new ObservableCollection(); + private readonly Dictionary itemLookup = new Dictionary(); + private readonly DispatcherTimer searchDelayTimer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(250) }; + private string lastSearchText = string.Empty; + private bool suppressTreeSelectionChanged; + + private TextBox searchTextBox; + private TreeView treeViewControl; + private ScrollViewer itemsScrollViewer; + + public ObservableCollection VisibleItems => visibleItems; + + public event EventHandler DropDownOpened; + public event EventHandler DropDownClosed; + + public HierarchicalSelectionControl() + { + InitializeComponent(); + searchDelayTimer.Tick += SearchDelayTimer_Tick; + } + + public bool CloseDropDownIfOpen() + { + if (ComboBoxControl?.IsDropDownOpen != true) + return false; + + ComboBoxControl.IsDropDownOpen = false; + return true; + } + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + EnsureTemplateParts(); + if (treeViewControl != null) + treeViewControl.ItemsSource = VisibleItems; + } + + #region DependencyProperties + + public ObservableCollection ItemsSource + { + get => (ObservableCollection)GetValue(ItemsSourceProperty); + set => SetValue(ItemsSourceProperty, value); + } + + public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register( + nameof(ItemsSource), + typeof(ObservableCollection), + typeof(HierarchicalSelectionControl), + new PropertyMetadata(null, OnItemsSourceChanged)); + + private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is HierarchicalSelectionControl control) + { + control.RebuildLookup(); + control.ApplyFilter(control.lastSearchText); + } + } + + public HierarchicalSelectionItem SelectedItem + { + get => (HierarchicalSelectionItem)GetValue(SelectedItemProperty); + set => SetValue(SelectedItemProperty, value); + } + + public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register( + nameof(SelectedItem), + typeof(HierarchicalSelectionItem), + typeof(HierarchicalSelectionControl), + new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnSelectedItemChanged)); + + private static void OnSelectedItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is HierarchicalSelectionControl control) + { + control.TryExpandToSelectedItem(); + control.SyncTreeSelectionWithSelectedItem(bringIntoView: false); + } + } + + public Brush ComboBoxBackground + { + get => (Brush)GetValue(ComboBoxBackgroundProperty); + set => SetValue(ComboBoxBackgroundProperty, value); + } + + public static readonly DependencyProperty ComboBoxBackgroundProperty = + DependencyProperty.Register(nameof(ComboBoxBackground), typeof(Brush), typeof(HierarchicalSelectionControl), new PropertyMetadata(Brushes.Transparent)); + + public string SearchPlaceholderText + { + get => (string)GetValue(SearchPlaceholderTextProperty); + set => SetValue(SearchPlaceholderTextProperty, value); + } + + public static readonly DependencyProperty SearchPlaceholderTextProperty = + DependencyProperty.Register(nameof(SearchPlaceholderText), typeof(string), typeof(HierarchicalSelectionControl), new PropertyMetadata(string.Empty)); + + #endregion + + #region UI Event Handling + + private void ComboBoxControl_DropDownOpened(object sender, EventArgs e) + { + EnsureTemplateParts(); + searchTextBox?.Focus(); + searchTextBox?.SelectAll(); + suppressTreeSelectionChanged = false; + SyncTreeSelectionWithSelectedItem(bringIntoView: true); + DropDownOpened?.Invoke(this, e); + } + + private void ComboBoxControl_DropDownClosed(object sender, EventArgs e) + { + searchDelayTimer.Stop(); + suppressTreeSelectionChanged = false; + DropDownClosed?.Invoke(this, e); + } + + private void SearchTextBox_TextChanged(object sender, TextChangedEventArgs e) + { + searchDelayTimer.Stop(); + searchDelayTimer.Start(); + } + + private void SearchDelayTimer_Tick(object sender, EventArgs e) + { + searchDelayTimer.Stop(); + lastSearchText = searchTextBox?.Text ?? string.Empty; + ApplyFilter(lastSearchText); + } + + private void TreeViewControl_SelectedItemChanged(object sender, RoutedPropertyChangedEventArgs e) + { + if (suppressTreeSelectionChanged) + return; + + if (e.NewValue is HierarchicalSelectionItem selected) + { + var original = ResolveOriginalItem(selected); + if (original != null && !Equals(SelectedItem, original)) + { + SelectedItem = original; + } + + suppressTreeSelectionChanged = true; + ComboBoxControl.IsDropDownOpen = false; + } + } + + #endregion + + #region Data Preparation and Filtering + + private HierarchicalSelectionItem ResolveOriginalItem(HierarchicalSelectionItem item) + { + if (item == null) + return null; + + if (!string.IsNullOrWhiteSpace(item.Id) && itemLookup.TryGetValue(item.Id, out var original)) + return original; + + return null; + } + + private void RebuildLookup() + { + itemLookup.Clear(); + + if (ItemsSource == null) + return; + + foreach (var entry in ItemsSource.SelectMany(item => item.SelfAndDescendants())) + { + if (string.IsNullOrWhiteSpace(entry.Id)) + continue; + + itemLookup[entry.Id] = entry; + } + } + + private void ApplyFilter(string searchText) + { + visibleItems.Clear(); + + if (ItemsSource == null) + return; + + if (string.IsNullOrWhiteSpace(searchText)) + { + foreach (var item in ItemsSource) + { + item.SetExpandedRecursive(false); + visibleItems.Add(item); + } + + TryExpandToSelectedItem(); + SyncTreeSelectionWithSelectedItem(bringIntoView: false); + return; + } + + var comparison = StringComparison.CurrentCultureIgnoreCase; + + foreach (var root in ItemsSource) + { + var clone = root.CloneBranch(node => + node.FullPath?.IndexOf(searchText, comparison) >= 0 || + node.DisplayName?.IndexOf(searchText, comparison) >= 0); + + if (clone == null) + continue; + + clone.SetExpandedRecursive(true); + visibleItems.Add(clone); + } + + // If the selected item is part of current results, keep it visually selected. + SyncTreeSelectionWithSelectedItem(bringIntoView: false); + } + + private void TryExpandToSelectedItem() + { + if (SelectedItem == null || string.IsNullOrWhiteSpace(SelectedItem.Id)) + return; + + if (!string.IsNullOrWhiteSpace(lastSearchText)) + return; + + var chain = SelectedItem; + while (chain != null) + { + chain.IsExpanded = true; + chain = chain.Parent; + } + } + + #endregion + + #region Tree Selection Sync + + private void SyncTreeSelectionWithSelectedItem(bool bringIntoView) + { + if (SelectedItem == null || string.IsNullOrWhiteSpace(SelectedItem.Id)) + return; + + EnsureTemplateParts(); + if (treeViewControl == null) + return; + + // Wait for popup/template layout to finish so item containers are generated. + Dispatcher.BeginInvoke(new Action(() => + { + var target = FindVisibleItemById(VisibleItems, SelectedItem.Id); + if (target == null) + return; + + var ancestor = target.Parent; + while (ancestor != null) + { + ancestor.IsExpanded = true; + ancestor = ancestor.Parent; + } + + treeViewControl.UpdateLayout(); + var targetContainer = GetTreeViewItemContainer(treeViewControl, target); + if (targetContainer == null) + return; + + suppressTreeSelectionChanged = true; + try + { + targetContainer.IsSelected = true; + if (bringIntoView) + targetContainer.BringIntoView(); + } + finally + { + suppressTreeSelectionChanged = false; + } + }), DispatcherPriority.Loaded); + } + + private static HierarchicalSelectionItem FindVisibleItemById(IEnumerable items, string id) + { + if (items == null || string.IsNullOrWhiteSpace(id)) + return null; + + foreach (var item in items) + { + if (item == null) + continue; + + if (string.Equals(item.Id, id, StringComparison.OrdinalIgnoreCase)) + return item; + + var childMatch = FindVisibleItemById(item.Children, id); + if (childMatch != null) + return childMatch; + } + + return null; + } + + private static TreeViewItem GetTreeViewItemContainer(ItemsControl root, object targetItem) + { + if (root == null || targetItem == null) + return null; + + var directContainer = root.ItemContainerGenerator.ContainerFromItem(targetItem) as TreeViewItem; + if (directContainer != null) + return directContainer; + + foreach (var child in root.Items) + { + var childContainer = root.ItemContainerGenerator.ContainerFromItem(child) as TreeViewItem; + if (childContainer == null) + continue; + + childContainer.UpdateLayout(); + var result = GetTreeViewItemContainer(childContainer, targetItem); + if (result != null) + return result; + } + + return null; + } + + #endregion + + #region Template and Scroll Handling + + private void EnsureTemplateParts() + { + if (treeViewControl == null) + { + treeViewControl = ComboBoxControl.Template.FindName("PART_TreeView", ComboBoxControl) as TreeView; + if (treeViewControl != null) + { + treeViewControl.SelectedItemChanged += TreeViewControl_SelectedItemChanged; + treeViewControl.ItemsSource = VisibleItems; + } + } + + if (searchTextBox == null) + { + searchTextBox = ComboBoxControl.Template.FindName("PART_SearchTextBox", ComboBoxControl) as TextBox; + if (searchTextBox != null) + searchTextBox.TextChanged += SearchTextBox_TextChanged; + } + + if (itemsScrollViewer == null) + { + itemsScrollViewer = ComboBoxControl.Template.FindName("PART_ItemsScrollViewer", ComboBoxControl) as ScrollViewer; + } + } + + private void ItemsScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e) + { + var scroller = itemsScrollViewer ?? sender as ScrollViewer; + if (scroller == null || scroller.ScrollableHeight <= 0) + return; + + var lines = SystemParameters.WheelScrollLines; + if (lines < 0) + { + if (e.Delta < 0) + scroller.PageDown(); + else + scroller.PageUp(); + e.Handled = true; + return; + } + + if (lines == 0) + { + scroller.ScrollToVerticalOffset(scroller.VerticalOffset - e.Delta); + e.Handled = true; + return; + } + + var direction = e.Delta < 0 ? 1 : -1; + var stepCount = Math.Max(1, Math.Abs(e.Delta) / 120) * lines; + for (var i = 0; i < stepCount; i++) + { + if (direction > 0) + scroller.LineDown(); + else + scroller.LineUp(); + } + + e.Handled = true; + } + + #endregion + + #region Keyboard + + protected override void OnPreviewKeyDown(KeyEventArgs e) + { + base.OnPreviewKeyDown(e); + + if (!IsEnabled) + return; + + if (!ComboBoxControl.IsDropDownOpen && (e.Key == Key.Enter || e.Key == Key.Down || e.Key == Key.Space)) + { + ComboBoxControl.IsDropDownOpen = true; + e.Handled = true; + return; + } + + if (ComboBoxControl.IsDropDownOpen && e.Key == Key.Escape) + { + ComboBoxControl.IsDropDownOpen = false; + e.Handled = true; + } + } + + #endregion + } +} diff --git a/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs b/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs index e74c3cf..687f1a5 100644 --- a/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs +++ b/FasdDesktopUi/Basics/UserControls/Ticket/CloseCaseDialogWithTicket.xaml.cs @@ -1,2802 +1,2844 @@ -using C4IT.FASD.Base; -using C4IT.FASD.Cockpit.Communication; -using C4IT.MultiLanguage; -using F4SD_AdaptableIcon.Enums; -using FasdDesktopUi.Basics.Helper; -using FasdDesktopUi.Basics.Models; -using FasdDesktopUi.Basics.Services.ProtocollService; -using FasdDesktopUi.Pages.TicketCompletion; -using MaterialIcons; -using System; -using System.Collections.Generic; -using System.Collections.ObjectModel; -using System.ComponentModel; -using System.Linq; -using System.Reflection; -using System.Text; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Input; -using System.Windows.Media; -using static C4IT.Logging.cLogManager; - -namespace FasdDesktopUi.Basics.UserControls -{ - public partial class CloseCaseDialogWithTicket : UserControl - { - private const double MinDialogContentHeightDip = 220d; - - #region Fields & Properties - private readonly Dictionary _errors = new Dictionary(); - - private readonly IValueConverter _languageConverter = new Converter.LanguageDefinitionsConverter(); - - private readonly List _openedWindows = new List(); - - private readonly cF4sdApiSearchResultRelation _newTicketRelation = new cF4sdApiSearchResultRelation() - { - id = Guid.NewGuid(), - DisplayName = cMultiLanguageSupport.GetItem("Header.Create.Ticket"), - Type = enumF4sdSearchResultClass.Ticket, - Identities = null, - Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.TicketCreation } - }; - - private readonly cF4sdApiSearchResultRelation _selectTicketRelation = new cF4sdApiSearchResultRelation() - { - id = Guid.NewGuid(), - DisplayName = cMultiLanguageSupport.GetItem("Header.Select.Ticket"), - Type = enumF4sdSearchResultClass.Ticket, - Identities = null, - Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.TicketSelect } - }; - - private readonly cF4sdApiSearchResultRelation _noTicketRelation = new cF4sdApiSearchResultRelation() - { - DisplayName = cMultiLanguageSupport.GetItem("Header.Skip.Ticket"), - Type = enumF4sdSearchResultClass.Ticket, - Identities = null, - Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.NoTicket } - }; - - private readonly cF4sdApiSearchResultRelation _removeAffectedAssetEntry = new cF4sdApiSearchResultRelation() - { - DisplayName = cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedAssetEntry"), - Type = enumF4sdSearchResultClass.Computer, - Identities = null, - Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.RemoveAffectedAssetEntry } - }; - - private const string CategoryTableNamePrimary = "M42Wpm-Ticket-Categories"; - private const string TicketDetailsTableName = "M42Wpm-Tickets"; - private const string TicketDetailsCategoryIdColumnName = "CategoryId"; - - private static readonly Brush SharedValidationBorderBrush = CreateValidationBrush(); - private static readonly Brush DefaultTextBoxBorderBrush = CreateDefaultTextBoxBorderBrush(); - private static Brush CreateValidationBrush() - { - var brush = new SolidColorBrush(Color.FromRgb(0xF5, 0x7C, 0x73)); - if (brush.CanFreeze) - brush.Freeze(); - return brush; - } - private static Brush CreateDefaultTextBoxBorderBrush() - { - var brush = new SolidColorBrush(Color.FromRgb(0xDE, 0xE2, 0xE6)); - if (brush.CanFreeze) - brush.Freeze(); - return brush; - } - - private ObservableCollection categoryHierarchy = new ObservableCollection(); - private readonly Dictionary categoryLookup = new Dictionary(StringComparer.OrdinalIgnoreCase); - private bool isCategoryLoading; - private Brush defaultCategoryBorderBrush; - private Brush defaultQuickTicketBorderBrush; - private readonly Brush validationErrorBrush = SharedValidationBorderBrush; - private Brush defaultTicketStatusBorderBrush; - private Thickness? defaultCategoryBorderThickness; - private Thickness? defaultQuickTicketBorderThickness; - private Thickness? defaultTicketStatusBorderThickness; - - public bool AreCaseNotesMandatory => - cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.NotesMandatory ?? false; - - private static class TicketInfoKeys - { - public const string ActivityType = "ActivityType"; - public const string Asset = "Asset"; - public const string ServiceId = "ServiceId"; - public const string ServiceName = "ServiceName"; - public const string StatusId = "StatusId"; - public const string Category = "Category"; - public const string Summary = "Summary"; - public const string Special = "Special"; - } - - private static class TicketInfoValues - { - public const string ActivityTypeTicket = "SPSActivityTypeTicket"; - } - - private static class TicketSpecialValues - { - public const string TicketCreation = "TicketCreation"; - public const string TicketSelect = "TicketSelect"; - public const string NoTicket = "NoTicket"; - public const string RemoveAffectedAssetEntry = "RemoveAffectedAssetEntry"; - public const string RemoveAffectedServiceEntry = "RemoveAffectedServiceEntry"; - } - - private static class ValidationPropertyNames - { - public const string SelectedTicket = nameof(SelectedTicket); - public const string SelectedCategory = nameof(SelectedCategory); - public const string QuickTicketSelection = nameof(QuickTicketSelection); - public const string TicketSummaryTextBox = nameof(TicketSummaryTextBox); - public const string TicketStatusCombobox = nameof(TicketStatusCombobox); - public const string CaseNotesPreview = nameof(CaseNotesPreview); - public const string SolutionTextbox = "SolutionTextbox"; - public const string ErrorTypeValue = "ErrorTypeValue"; - public const string ReminderDate = "ReminderDate"; - public const string HoldComment = "HoldComment"; - public const string SelectedRoleAndPerson = "SelectedRoleAndPerson"; - public const string ForwardComment = "ForwardComment"; - } - - private bool TryGetSelectedTicketInfo(string key, out string value) - { - value = null; - return SelectedTicket?.Infos != null && SelectedTicket.Infos.TryGetValue(key, out value); - } - - private string GetSelectedTicketInfoOrDefault(string key) => - TryGetSelectedTicketInfo(key, out var value) ? value : null; - - private static bool TryGetSpecialValue(cF4sdApiSearchResultRelation relation, out string specialValue) - { - specialValue = null; - return relation?.Infos != null && relation.Infos.TryGetValue(TicketInfoKeys.Special, out specialValue); - } - - private static bool RelationHasSpecialInfo(cF4sdApiSearchResultRelation relation, string expectedSpecialValue) => - TryGetSpecialValue(relation, out var specialValue) && - string.Equals(specialValue, expectedSpecialValue, StringComparison.OrdinalIgnoreCase); - - public bool IsTicket - { - get - { - return TryGetSelectedTicketInfo(TicketInfoKeys.ActivityType, out var activityType) - && string.Equals(activityType, TicketInfoValues.ActivityTypeTicket, StringComparison.OrdinalIgnoreCase); - } - } - - private bool _isTicketIntegrationActive; - public bool IsTicketIntegrationActive - { - get => _isTicketIntegrationActive; - private set => _isTicketIntegrationActive = value; - } - - public bool EnableHoldTicketAction - { - get { return (bool)GetValue(EnableHoldTicketActionProperty); } - set { SetValue(EnableHoldTicketActionProperty, value); } - } - - public static readonly DependencyProperty EnableHoldTicketActionProperty = - DependencyProperty.Register("EnableHoldTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); - - public bool EnableCloseTicketAction - { - get { return (bool)GetValue(EnableCloseTicketActionProperty); } - set { SetValue(EnableCloseTicketActionProperty, value); } - } - - public static readonly DependencyProperty EnableCloseTicketActionProperty = - DependencyProperty.Register("EnableCloseTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); - - public bool EnableSaveTicketAction - { - get { return (bool)GetValue(EnableSaveTicketActionProperty); } - set { SetValue(EnableSaveTicketActionProperty, value); } - } - - public static readonly DependencyProperty EnableSaveTicketActionProperty = - DependencyProperty.Register("EnableSaveTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); - - public bool EnableForwardTicketAction - { - get { return (bool)GetValue(EnableForwardTicketActionProperty); } - set { SetValue(EnableForwardTicketActionProperty, value); } - } - - public static readonly DependencyProperty EnableForwardTicketActionProperty = - DependencyProperty.Register("EnableForwardTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); - - private cF4sdApiSearchResultRelation _selectedTicket; - - public cF4sdApiSearchResultRelation SelectedTicket - { - get => _selectedTicket; - set - { - _selectedTicket = value; - //SelectedComputer = null; - - UpdateSelectedTicketControl(); - CheckAffectedAssetIsCurrentAsset(); - CheckAffectedServiceIsCurrentService(); - UpdateAffectedAssetLabel(); - UpdateAffectedServiceLabel(); - UpdateAffectedAssetComboBox(); - ShowAssetWarningTicketAction = IsTicket; - ValidateProperty(ValidationPropertyNames.SelectedTicket); - EnableHoldTicketAction = _selectedTicket == null || SelectedTicket == _selectTicketRelation || selectedTicketIsNewTicket; - if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && - Enum.TryParse(statusIdString, true, out enumTicketStatus statusId)) - { - EnableHoldTicketAction = statusId != enumTicketStatus.OnHold; - } - TrySelectTicketCategoryFromTicketInfos(); - _ = EnsureSelectedTicketCategoryFromDetailsAsync(_selectedTicket); - } - } - - private bool selectedTicketIsNewTicket - { - get => SelectedTicket == _newTicketRelation; - } - - #region SelectedComputer DependencyProperty - public static readonly DependencyProperty SelectedComputerProperty = - DependencyProperty.Register("SelectedComputer", typeof(cF4sdApiSearchResultRelation), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(null)); - - public cF4sdApiSearchResultRelation SelectedComputer - { - get { return (cF4sdApiSearchResultRelation)GetValue(SelectedComputerProperty); } - set - { - SetValue(SelectedComputerProperty, value); - CheckAffectedAssetIsCurrentAsset(); - } - } - #endregion - - public bool ShowAssetWarningTicketAction - { - get { return (bool)GetValue(ShowAssetWarningTicketActionProperty); } - set { SetValue(ShowAssetWarningTicketActionProperty, value); } - } - - public static readonly DependencyProperty ShowAssetWarningTicketActionProperty = - DependencyProperty.Register("ShowAssetWarningTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); - - #region SelectedService DependencyProperty - - public static readonly DependencyProperty SelectedServiceProperty = DependencyProperty.Register( - "SelectedService", - typeof(KeyValuePair), - typeof(CloseCaseDialogWithTicket), - new PropertyMetadata(default(KeyValuePair), OnSelectedServiceChanged)); - - public KeyValuePair SelectedService - { - get { return (KeyValuePair)GetValue(SelectedServiceProperty); } - set - { - SetValue(SelectedServiceProperty, value); - CheckAffectedServiceIsCurrentService(); - } - } - private static void OnSelectedServiceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - var control = (CloseCaseDialogWithTicket)d; - var newValue = (KeyValuePair)e.NewValue; - control.CheckAffectedServiceIsCurrentService(); - } - #endregion - - #region SelectedCategory DependencyProperty - - public static readonly DependencyProperty SelectedCategoryProperty = DependencyProperty.Register( - "SelectedCategory", - typeof(HierarchicalSelectionItem), - typeof(CloseCaseDialogWithTicket), - new PropertyMetadata(null, OnSelectedCategoryChanged)); - - public HierarchicalSelectionItem SelectedCategory - { - get { return (HierarchicalSelectionItem)GetValue(SelectedCategoryProperty); } - set { SetValue(SelectedCategoryProperty, value); } - } - - private static void OnSelectedCategoryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is CloseCaseDialogWithTicket instance) - { - instance.LogSelectedCategoryChanged(e.NewValue as HierarchicalSelectionItem); - instance.ValidateProperty(ValidationPropertyNames.SelectedCategory); - } - } - - #endregion - - private void LogSelectedCategoryChanged(HierarchicalSelectionItem category) - { - try - { - var fullPath = category == null - ? "" - : string.IsNullOrWhiteSpace(category.FullPath) ? category.DisplayName : category.FullPath; - var id = category == null || string.IsNullOrWhiteSpace(category.Id) ? "" : category.Id; - LogEntry($"[CloseCaseDialog] SelectedCategory updated -> {fullPath} (Id={id})"); - } - catch (Exception ex) - { - LogException(ex); - } - } - - public bool ShowServiceHasBeenChangedWarning - { - get { return ServiceHasBeenChanged && SetOrUpdateServiceInTicket; } - } - public bool ShowAssetHasBeenChangedWarning - { - get { return AssetHasBeenChanged && SetOrUpdateComputerInTicket; } - } - - #region AssetHasBeenChanged DependencyProperty - - public static readonly DependencyProperty AssetHasBeenChangedProperty = - DependencyProperty.Register("AssetHasBeenChanged", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); - - public bool AssetHasBeenChanged - { - get { return (bool)GetValue(AssetHasBeenChangedProperty); } - set { SetValue(AssetHasBeenChangedProperty, value); } - } - - #endregion - - #region SetOrUpdateComputerInTicket DependencyProperty - - public static readonly DependencyProperty SetOrUpdateComputerInTicketProperty = - DependencyProperty.Register("SetOrUpdateComputerInTicket", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true, OnSetOrUpdateComputerInTicketChanged)); - - private static void OnSetOrUpdateComputerInTicketChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is CloseCaseDialogWithTicket instance) - instance.CheckAffectedAssetIsCurrentAsset(); - } - - public bool SetOrUpdateComputerInTicket - { - get { return (bool)GetValue(SetOrUpdateComputerInTicketProperty); } - set { SetValue(SetOrUpdateComputerInTicketProperty, value); } - } - - #endregion - - private bool _skipTicketPillSelected; - - public bool SkipTicketPillSelected - { - get { return _skipTicketPillSelected; } - set { _skipTicketPillSelected = value; } - } - - private bool _newTicketPillSelected; - - public bool NewTicketPillSelected - { - get { return _newTicketPillSelected; } - set - { - _newTicketPillSelected = value; - ValidateProperty(ValidationPropertyNames.SelectedTicket); - - } - } - - #region SetOrUpdateServiceInTicket DependencyProperty - - public static readonly DependencyProperty SetOrUpdateServiceInTicketProperty = - DependencyProperty.Register("SetOrUpdateServiceInTicket", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false, OnSetOrUpdateServiceInTicketChanged)); - - private static void OnSetOrUpdateServiceInTicketChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is CloseCaseDialogWithTicket instance) - instance.CheckAffectedServiceIsCurrentService(); - } - - public bool SetOrUpdateServiceInTicket - { - get { return (bool)GetValue(SetOrUpdateServiceInTicketProperty); } - set { SetValue(SetOrUpdateServiceInTicketProperty, value); } - } - #endregion - - #region ServiceHasBeenChanged DependencyProperty - - public static readonly DependencyProperty ServiceHasBeenChangedProperty = - DependencyProperty.Register("ServiceHasBeenChanged", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); - - public bool ServiceHasBeenChanged - { - get { return (bool)GetValue(ServiceHasBeenChangedProperty); } - set { SetValue(ServiceHasBeenChangedProperty, value); } - } - - #endregion - - public static readonly DependencyProperty ComputerRelationsProperty = - DependencyProperty.Register("ComputerRelations", typeof(List), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(new List(), OnComputerRelationsChanged)); - - private static void OnComputerRelationsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - if (d is CloseCaseDialogWithTicket instance) - { - //instance.CheckAffectedAssetIsCurrentAsset(); - } - } - - public List ComputerRelations - { - get { return (List)GetValue(ComputerRelationsProperty); } - set { SetValue(ComputerRelationsProperty, value); } - } - - public bool SupportNotepad { get; private set; } = false; - - public static EventHandler TicketNotepadChanged { get; set; } - - #region DataProvider - - public cSupportCaseDataProvider DataProvider - { - get { return (cSupportCaseDataProvider)GetValue(DataProviderProperty); } - set { SetValue(DataProviderProperty, value); } - } - - public static readonly DependencyProperty DataProviderProperty = - DependencyProperty.Register("DataProvider", typeof(cSupportCaseDataProvider), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(null, DataProviderChanged)); - - private static async void DataProviderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - try - { - if (!(d is CloseCaseDialogWithTicket me)) - return; - - - me.SelectedTicket = me.SelectedTicket ?? me._selectTicketRelation; - - me.UpdateSelectedTicketControl(); - me.UpdateTicketSelection(); - - me.AddCopyTemplates(); - me.UpdateAffectedAssetLabel(); - me.UpdateAffectedServiceLabel(); - me.UpdateAffectedAssetComboBox(); - - me.ServiceSelectionControl.SearchDataChanged = me.HandleServiceSearchDataChanged; - me.ServiceSelectionControl.ParentElement = me.MainStack; - me.ServiceSelectionControl.ParentIndex = me.MainStack.Children.IndexOf(me.ServiceSelectionControl); - - me.AddNewOrExistingOrNoneTicketSelection(); - me.UpdateCaseNotesPreview(); - me.UpdateTicketComponentVisibility(); - await me.InitializeCategorySelectionAsync(); - await me.UpdateQuickCallsComboBoxAsync(); - me.ValidateProperty(ValidationPropertyNames.SelectedCategory); - me.ValidateProperty(ValidationPropertyNames.QuickTicketSelection); - } - catch (Exception E) - { - LogException(E); - } - - } - - #endregion - - #endregion - string lastServiceSearch = string.Empty; - - private TicketCompletion parentWindow; - - public CloseCaseDialogWithTicket() - { - InitializeComponent(); - this.Unloaded += CloseCaseDialogWithTicket_Unloaded; - this.Loaded += CloseCaseDialogWithTicket_Loaded; - defaultCategoryBorderBrush = CategoryValidationBorder?.BorderBrush?.CloneCurrentValue(); - defaultQuickTicketBorderBrush = QuickTicketValidationBorder?.BorderBrush?.CloneCurrentValue(); - defaultTicketStatusBorderBrush = TicketStatusValidationBorder?.BorderBrush?.CloneCurrentValue(); - if (validationErrorBrush is Freezable freezableBrush && freezableBrush.CanFreeze) - freezableBrush.Freeze(); - - DependencyPropertyDescriptor dpd = - DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock)); - - dpd?.AddValueChanged(CaseNotesPreview, TicketCaseNotesTextBlock_TextChanged); - - SupportNotepad = true; - } - - private void CloseCaseDialogWithTicket_Loaded(object sender, RoutedEventArgs e) - { - Window _parentWindow = Window.GetWindow(this); - - if (!(_parentWindow is TicketCompletion _msgBox)) - return; - - _parentWindow.Closing += ParentWindow_Closing; - parentWindow = _msgBox; - parentWindow.SetButtonStateYes(false, "Initial gesperrt."); - parentWindow.SetButtonStateNo(true, cMultiLanguageSupport.GetItem("Dialog.CloseCase.Cancel")); - - ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); - ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); - ValidateProperty(ValidationPropertyNames.CaseNotesPreview); - ValidateProperty(ValidationPropertyNames.SelectedCategory); - ValidateProperty(ValidationPropertyNames.QuickTicketSelection); - } - private void CloseCaseDialogWithTicket_Unloaded(object sender, RoutedEventArgs e) - { - Window parentWindow = Window.GetWindow(this); - if (parentWindow != null) - { - parentWindow.Closing -= ParentWindow_Closing; - } - } - private void ParentWindow_Closing(object sender, CancelEventArgs e) - { - foreach (SelectionPill pill in NewOrExistingOrNoneTicketWrap.Children.OfType()) - { - SelectionPill.RemovePill(pill); - } - foreach (SelectionPill pill in CopyTemplateWrap.Children.OfType()) - { - SelectionPill.RemovePill(pill); - } - } - protected override void OnInitialized(EventArgs e) - { - try - { - base.OnInitialized(e); - IsTicketIntegrationActive = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles?.Any(role => string.Equals(role, "Cockpit.TicketAgent", StringComparison.OrdinalIgnoreCase)) ?? false; - cSupportCaseDataProvider.CaseNotesChanged += (sender, args) => UpdateCaseNotesPreview(); - } - catch (Exception E) - { - LogException(E); - } - } - - - - private void UpdateAffectedAssetLabel() - { - var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); - - var binding = new Binding - { - Converter = _languageConverter, - ConverterParameter = NewTicketPillSelected || string.IsNullOrEmpty(computerName) ? "Dialog.CloseCase.SetAffectedAssetLabel" : "Dialog.CloseCase.UpdateAffectedAssetLabel" - }; - - SetOrUpdateComputerInTicketLabel.SetBinding(TextBlock.TextProperty, binding); - } - private void UpdateAffectedServiceLabel() - { - var serviceId = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); - - var binding = new Binding - { - Converter = _languageConverter, - ConverterParameter = NewTicketPillSelected || string.IsNullOrEmpty(serviceId) || serviceId == Guid.Empty.ToString() ? "Dialog.CloseCase.SetAffectedServiceLabel" : "Dialog.CloseCase.UpdateAffectedServiceLabel" - }; - - SetOrUpdateServiceInTicketLabel.SetBinding(TextBlock.TextProperty, binding); - } - - private bool checkTicketActive() - { - var _retVal = IsTicketIntegrationActive; - if (cFasdCockpitCommunicationBase.Instance.IsDemo()) - _retVal = DataProvider.HealthCardDataHelper?.HealthCardRawData?.Tables?.ContainsKey("M42Wpm-User-NewTicket") ?? false; - return _retVal; - } - - private void UpdateTicketComponentVisibility() - { - try - { - if (DataProvider is null) - return; - - var _isVisible = checkTicketActive() && !_skipTicketPillSelected; - - TicketSelectionCategory.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed; - StatusSelectionBorder.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed; - CopyDisclaimerTextBox.Visibility = _isVisible ? Visibility.Collapsed : Visibility.Visible; - } - catch (Exception E) - { - LogException(E); - } - } - - private UIElement GetTicketUiElement(cF4sdApiSearchResultRelation ticketRelation) - { - try - { - Border outputBorder = new Border(); - outputBorder.MouseLeftButtonUp += TicketRelation_MouseLeftButtonUp; - outputBorder.TouchDown += TicketRelation_TouchDown; - - outputBorder.SetResourceReference(StyleProperty, "Menu.SubCategory"); - outputBorder.Tag = ticketRelation; - - Grid contentGrid = new Grid(); - outputBorder.Child = contentGrid; - contentGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); - contentGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); - - AdaptableIcon.AdaptableIcon ticketIcon = new AdaptableIcon.AdaptableIcon() { SelectedInternIcon = enumInternIcons.f4sd_outline }; - - if (RelationHasSpecialInfo(ticketRelation, TicketSpecialValues.TicketCreation)) - { - ticketIcon.SelectedInternIcon = enumInternIcons.misc_plus; - } - else if (RelationHasSpecialInfo(ticketRelation, TicketSpecialValues.NoTicket)) - { - ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_block; - } - else if (ticketRelation.Infos.TryGetValue(TicketInfoKeys.StatusId, out string ticketStatusId)) - { - Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus); - - switch (ticketStatus) - { - case enumTicketStatus.New: - case enumTicketStatus.InProgress: - case enumTicketStatus.OnHold: - ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts; - break; - case enumTicketStatus.Closed: - ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; - break; - } - } - else - { - ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; - } - - contentGrid.Children.Add(ticketIcon); - StackPanel ticketTextStack = new StackPanel() { Margin = new Thickness(15, 0, 15, 0), VerticalAlignment = VerticalAlignment.Center, IsHitTestVisible = false }; - Grid.SetColumn(ticketTextStack, 1); - contentGrid.Children.Add(ticketTextStack); - - Border ticketNameBorder = new Border() { ClipToBounds = true }; - ticketTextStack.Children.Add(ticketNameBorder); - - TextBlock ticketNameTextBlock = new TextBlock() { Text = ticketRelation.DisplayName, TextTrimming = TextTrimming.CharacterEllipsis }; - ticketNameBorder.Child = ticketNameTextBlock; - - Border ticketDescriptionBorder = new Border() { ClipToBounds = true }; - ticketTextStack.Children.Add(ticketDescriptionBorder); - - TextBlock ticketDescriptionTextBlock = null; - if (ticketRelation.Infos.TryGetValue(TicketInfoKeys.Summary, out string ticketSummary)) - { - ticketDescriptionTextBlock = new TextBlock() { Text = ticketSummary, TextTrimming = TextTrimming.CharacterEllipsis, FontWeight = FontWeights.UltraLight }; - ticketDescriptionBorder.Child = ticketDescriptionTextBlock; - } - - outputBorder.MouseEnter += (sender, e) => - { - try - { - cUtility.SetTickerTextAnimation(ticketNameTextBlock, ticketNameBorder); - - if (ticketDescriptionTextBlock != null) - cUtility.SetTickerTextAnimation(ticketDescriptionTextBlock, ticketDescriptionBorder); - } - catch (Exception E) - { - LogException(E); - } - }; - outputBorder.MouseLeave += (sender, e) => - { - try - { - ticketNameTextBlock.TextTrimming = TextTrimming.CharacterEllipsis; - ticketNameTextBlock.BeginAnimation(MarginProperty, null); - - ticketNameBorder.ClearValue(WidthProperty); - ticketNameTextBlock.ClearValue(WidthProperty); - - if (ticketDescriptionTextBlock != null) - { - ticketDescriptionTextBlock.TextTrimming = TextTrimming.CharacterEllipsis; - ticketDescriptionTextBlock.BeginAnimation(MarginProperty, null); - } - } - catch (Exception E) - { - LogException(E); - } - }; - - - return outputBorder; - } - catch (Exception E) - { - LogException(E); - } - - return null; - } - - private void UpdateSelectedTicketControl() - { - try - { - if (SelectedTicket is null) - return; - - TicketIcon.SelectedInternIcon = null; - TicketIcon.SelectedMaterialIcon = null; - TicketTextBlock.Text = SelectedTicket.DisplayName; - - if (SelectedTicket.Infos.TryGetValue(TicketInfoKeys.Summary, out var ticketSummary)) - TicketSummaryTextBox.Text = ticketSummary; - else - TicketSummaryTextBox.Text = string.Empty; - - if (RelationHasSpecialInfo(SelectedTicket, TicketSpecialValues.TicketCreation)) - { - TicketIcon.SelectedInternIcon = enumInternIcons.misc_plus; - } - else if (RelationHasSpecialInfo(SelectedTicket, TicketSpecialValues.NoTicket)) - { - TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_block; - } - else if (SelectedTicket.Infos.TryGetValue(TicketInfoKeys.StatusId, out string ticketStatusId)) - { - Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus); - - switch (ticketStatus) - { - case enumTicketStatus.New: - case enumTicketStatus.InProgress: - case enumTicketStatus.OnHold: - TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts; - break; - case enumTicketStatus.Closed: - TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; - break; - } - } - else - { - TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; - } - } - catch (Exception E) - { - LogException(E); - } - } - - private void CheckAffectedAssetIsCurrentAsset() - { - - try - { - WarningAssetHasBeenChanged.DataContext = this; - Binding visibilityBinding = new Binding(nameof(ShowAssetHasBeenChangedWarning)) - { - Converter = new BooleanToVisibilityConverter(), - }; - if (DataProvider == null) return; - - var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); - if (string.IsNullOrEmpty(computerName) || SelectedComputer == null) - { - AssetHasBeenChanged = false; - } - else - { - AssetHasBeenChanged = !SelectedComputer.DisplayName.Equals(computerName, StringComparison.OrdinalIgnoreCase); - } - WarningAssetHasBeenChanged.SetBinding(VisibilityProperty, visibilityBinding); - } - catch (Exception e) - { - LogException(e); - } - } - - private void CheckAffectedServiceIsCurrentService() - { - - try - { - WarningServiceHasBeenChanged.DataContext = this; - Binding visibilityBinding = new Binding(nameof(ShowServiceHasBeenChangedWarning)) - { - Converter = new BooleanToVisibilityConverter(), - }; - if (DataProvider == null) return; - - var service = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); - if (string.IsNullOrEmpty(service) || service == Guid.Empty.ToString() || SelectedService.Value == null) - { - ServiceHasBeenChanged = false; - } - else - { - ServiceHasBeenChanged = !SelectedService.Value.ToString().Equals(service, StringComparison.OrdinalIgnoreCase); - } - WarningServiceHasBeenChanged.SetBinding(VisibilityProperty, visibilityBinding); - } - catch (Exception e) - { - LogException(e); - } - } - - private void UpdateAffectedAssetComboBox() - { - try - { - if (DataProvider?.CaseRelations.TryGetValue(enumFasdInformationClass.Computer, out var computerRelationsTemp) != true) - return; - ComputerRelations = new List(computerRelationsTemp); - var currentlySelectedId = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer)?.Id; - var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); - - - // Direktes Hinzufügen von Standardoptionen - var defaultOptions = new List(); - - // Hinzufügen basierend auf der Verfügbarkeit eines ausgewählten Elements - if (SelectedTicket != _newTicketRelation && !string.IsNullOrEmpty(computerName)) - { - var stringTemplate = cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedAssetEntry"); - _removeAffectedAssetEntry.DisplayName = string.Format(stringTemplate, computerName); - defaultOptions.AddRange(new[] { _removeAffectedAssetEntry }); - } - else - { - ComputerRelations.Remove(_removeAffectedAssetEntry); - } - var matchingRelation = ComputerRelations.FirstOrDefault(relation => relation.DisplayName == computerName); - - if (matchingRelation != null && !selectedTicketIsNewTicket) - { - ComputerRelations.Remove(matchingRelation); - } - ComputerRelations = ComputerRelations.Concat(defaultOptions).ToList(); - - var currentlySelectedComputer = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer); - if (currentlySelectedComputer != null) - SelectedComputer = ComputerRelations.FirstOrDefault(c => c.id == currentlySelectedComputer.Id); - else if (ComputerSelection.Items.Count > 0) - ComputerSelection.SelectedIndex = 0; - - if (currentlySelectedComputer == null || ComputerRelations.Any(x => RelationHasSpecialInfo(x, TicketSpecialValues.RemoveAffectedAssetEntry))) - SetOrUpdateComputerInTicket = false; - if (NewTicketPillSelected) - SetOrUpdateComputerInTicket = true; - - - } - catch (Exception e) - { - LogException(e); - } - } - - - private async void HandleServiceSearchDataChanged(object sender, cF4sdHealthSelectionDataRequest e) => await UpdateServiceSelectionControlAsync(e); - - private async Task UpdateServiceSelectionControlAsync(cF4sdHealthSelectionDataRequest requestData) - { - - try - { - string adDnUser = string.Empty; - - if (!cFasdCockpitCommunicationBase.Instance.IsDemo()) - { - if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-User", out var adDnUserParameter) && - !string.IsNullOrEmpty(adDnUserParameter.GetValue())) - { - adDnUser = adDnUserParameter.GetValue(); - } - else - { - return; - } - } - - requestData.Identities = DataProvider.Identities; - requestData.Table = "M42Wpm-Ticket-CloseCase-Services"; - requestData.FilterParams = new List { adDnUser }; - requestData.ResetFilter = ServiceSelectionControl.ResetFilter; - - if (string.IsNullOrEmpty(lastServiceSearch) || !lastServiceSearch.Equals(requestData.Search, StringComparison.OrdinalIgnoreCase)) - { - var resServiceCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); - ServiceSelectionControl.TotalItemCount = resServiceCount; - lastServiceSearch = requestData.Search; - } - - var serviceData = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); - var servicesList = GetServiceSelectionData(serviceData); - - var service = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); - var serviceName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceName); - if (!string.IsNullOrEmpty(service) && Guid.Empty.ToString() != service) - { - - servicesList.Add(new KeyValuePair(string.Format(cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedServiceEntry"), serviceName), TicketSpecialValues.RemoveAffectedServiceEntry)); - var itemToRemove = servicesList.FirstOrDefault(item => item.Value is string && (string)item.Value == service); - if (!itemToRemove.Equals(default(KeyValuePair))) - { - servicesList.Remove(itemToRemove); - } - } - else - { - var itemToRemove = servicesList.FirstOrDefault(x => string.Equals(x.Value.ToString(), TicketSpecialValues.RemoveAffectedServiceEntry, StringComparison.OrdinalIgnoreCase)); - if (itemToRemove.Key != null) - { - servicesList.Remove(itemToRemove); - } - } - ServiceSelectionControl.ItemData = servicesList; - } - catch (Exception E) - { - LogException(E); - } - } - - private ObservableCollection> GetServiceSelectionData(cF4SDHealthCardRawData.cHealthCardTable dataTable) - { - try - { - if (dataTable is null || dataTable.Name != "M42Wpm-Ticket-CloseCase-Services") - return null; - - if (!dataTable.Columns.TryGetValue("id", out var idColumn)) - return null; - - dataTable.Columns.TryGetValue("Name", out var nameColumn); - - var zippedKeyValuePairs = idColumn.Values.Zip(nameColumn.Values, (id, display) => new KeyValuePair(display.ToString(), id)); - - return new ObservableCollection>(zippedKeyValuePairs); - } - catch (Exception E) - { - LogException(E); - } - - return null; - } - - private async Task InitializeCategorySelectionAsync() - { - if (isCategoryLoading) - return; - - try - { - if (DataProvider == null || CategorySelectionControl == null) - return; - - isCategoryLoading = true; - - if (await TryPopulateCategoryHierarchyAsync(CategoryTableNamePrimary)) - { - CategorySelectionControl.ItemsSource = categoryHierarchy; - TrySelectTicketCategoryFromTicketInfos(); - } - } - catch (Exception E) - { - LogException(E); - } - finally - { - isCategoryLoading = false; - ValidateProperty(ValidationPropertyNames.SelectedCategory); - } - } - - private async Task TryPopulateCategoryHierarchyAsync(string tableName) - { - try - { - const int defaultPageSize = 250; - - var requestData = new cF4sdHealthSelectionDataRequest - { - Identities = DataProvider.Identities, - Table = tableName, - Page = 0, - PageSize = defaultPageSize, - Search = string.Empty - }; - - var totalCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); - var effectivePageSize = requestData.PageSize > 0 ? requestData.PageSize : defaultPageSize; - var pageCount = Math.Max(1, (int)Math.Ceiling((double)totalCount / Math.Max(1, effectivePageSize))); - - var flatItems = new Dictionary(StringComparer.OrdinalIgnoreCase); - - for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) - { - requestData.Page = pageIndex; - requestData.PageSize = effectivePageSize; - - var categoryTable = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); - bool rowAdded = false; - - foreach (var item in ConvertCategoryTable(categoryTable)) - { - if (string.IsNullOrWhiteSpace(item.Id)) - continue; - - flatItems[item.Id] = item; - rowAdded = true; - } - - if (!rowAdded && categoryTable == null) - return false; - } - - var hierarchy = HierarchicalSelectionItem.BuildTree(flatItems.Values); - if (hierarchy == null || hierarchy.Count == 0) - return false; - - categoryHierarchy = hierarchy; - UpdateCategoryLookup(); - return true; - } - catch (Exception E) - { - LogException(E); - return false; - } - } - - private IEnumerable ConvertCategoryTable(cF4SDHealthCardRawData.cHealthCardTable dataTable) - { - if (dataTable == null || dataTable.Columns == null) - yield break; - - if (!dataTable.Columns.TryGetValue("id", out var idColumn)) - yield break; - - if (!dataTable.Columns.TryGetValue("Name", out var nameColumn)) - yield break; - - if (!dataTable.Columns.TryGetValue("parentValue", out cF4SDHealthCardRawData.cHealthCardTableColumn parentIdColumn)) - dataTable.Columns.TryGetValue("Parent_Value", out parentIdColumn); - if (!dataTable.Columns.TryGetValue("parent", out cF4SDHealthCardRawData.cHealthCardTableColumn parentNameColumn)) - dataTable.Columns.TryGetValue("Parent", out parentNameColumn); - - for (int index = 0; index < idColumn.Values.Count; index++) - { - var id = idColumn.Values[index]?.ToString(); - if (string.IsNullOrWhiteSpace(id)) - continue; - - var displayName = index < nameColumn.Values.Count ? nameColumn.Values[index]?.ToString() : string.Empty; - - string parentId = null; - if (parentIdColumn != null && index < parentIdColumn.Values.Count) - parentId = parentIdColumn.Values[index]?.ToString(); - - if (Guid.TryParse(parentId, out var parsedParentId) && parsedParentId == Guid.Empty) - parentId = null; - - var parentDisplayName = parentNameColumn != null && index < parentNameColumn.Values.Count - ? parentNameColumn.Values[index]?.ToString() - : null; - - yield return new HierarchicalSelectionItem - { - Id = id, - DisplayName = string.IsNullOrWhiteSpace(displayName) ? parentDisplayName ?? id : displayName, - ParentId = parentId, - ParentDisplayName = parentDisplayName - }; - } - } - - private void UpdateCategoryLookup() - { - categoryLookup.Clear(); - - if (categoryHierarchy == null) - return; - - foreach (var node in categoryHierarchy.SelectMany(item => item.SelfAndDescendants())) - { - if (!string.IsNullOrWhiteSpace(node.Id)) - categoryLookup[node.Id] = node; - } - } - - private void TrySelectTicketCategoryFromTicketInfos() - { - try - { - if (SelectedTicket?.Infos == null) - { - SelectedCategory = null; - return; - } - - if (!SelectedTicket.Infos.TryGetValue(TicketInfoKeys.Category, out var categoryId) || string.IsNullOrWhiteSpace(categoryId)) - { - SelectedCategory = null; - return; - } - - if (categoryLookup.TryGetValue(categoryId, out var categoryNode)) - SelectedCategory = categoryNode; - } - catch (Exception E) - { - LogException(E); - } - } - - private bool ShouldLoadCategoryFromDetails(cF4sdApiSearchResultRelation ticket) - { - if (ticket == null || ticket == _newTicketRelation || ticket == _selectTicketRelation || ticket == _noTicketRelation) - return false; - - if (ticket.Infos == null) - return true; - - if (!ticket.Infos.TryGetValue(TicketInfoKeys.Category, out var categoryValue) || string.IsNullOrWhiteSpace(categoryValue)) - return true; - - return !Guid.TryParse(categoryValue, out _); - } - - private async Task EnsureSelectedTicketCategoryFromDetailsAsync(cF4sdApiSearchResultRelation ticket) - { - try - { - if (!ShouldLoadCategoryFromDetails(ticket)) - return; - - var communication = cFasdCockpitCommunicationBase.Instance; - if (communication == null) - return; - - var request = new cF4sdHealthCardRawDataRequest - { - Tables = new List { TicketDetailsTableName }, - Identities = new cF4sdIdentityList - { - new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = ticket.id } - }, - MaxAge = 1 - }; - - var rawData = await communication.GetHealthCardData(request).ConfigureAwait(false); - if (rawData?.Tables == null) - return; - - if (!rawData.Tables.TryGetValue(TicketDetailsTableName, out var ticketTable)) - return; - - if (!ticketTable.Columns.TryGetValue(TicketDetailsCategoryIdColumnName, out var categoryColumn)) - return; - - var categoryId = categoryColumn.Values?.FirstOrDefault()?.ToString(); - if (string.IsNullOrWhiteSpace(categoryId)) - return; - - await Dispatcher.InvokeAsync(() => - { - if (SelectedTicket == null) - return; - - if (!ReferenceEquals(SelectedTicket, ticket) && SelectedTicket.id != ticket.id) - return; - - if (SelectedTicket.Infos == null) - SelectedTicket.Infos = new Dictionary(StringComparer.OrdinalIgnoreCase); - - SelectedTicket.Infos[TicketInfoKeys.Category] = categoryId; - TrySelectTicketCategoryFromTicketInfos(); - }); - } - catch (Exception E) - { - LogException(E); - } - } - - private Guid? GetSelectedCategoryGuid() - { - if (SelectedCategory == null || string.IsNullOrWhiteSpace(SelectedCategory.Id)) - return null; - - if (Guid.TryParse(SelectedCategory.Id, out var categoryGuid)) - return categoryGuid; - - return null; - } - - private async Task UpdateQuickCallsComboBoxAsync() - { - try - { - cF4sdHealthSelectionDataRequest requestData = new cF4sdHealthSelectionDataRequest - { - Identities = DataProvider.Identities, - Table = "M42Wpm-Ticket-QuickCalls" - }; - - var resultCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); - var quickCallsTable = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); - - if (quickCallsTable == null) return; - - if (!quickCallsTable.Columns.TryGetValue("Name", out var namesColumn) || - !quickCallsTable.Columns.TryGetValue("id", out var idsColumn)) - { - return; - } - - quickCallsTable.Columns.TryGetValue("Category", out var categoryColumn); - - var quickCallListe = new List(); - - for (int i = 0; i < idsColumn.Values.Count; i++) - { - var id = idsColumn.Values[i].ToString(); - var name = namesColumn.Values[i].ToString(); - - Guid? categoryId = null; - if (categoryColumn?.Values != null && i < categoryColumn.Values.Count) - { - var categoryValue = categoryColumn.Values[i]?.ToString(); - if (Guid.TryParse(categoryValue, out var parsedCategory)) - categoryId = parsedCategory; - } - - quickCallListe.Add(new QuickCallEntry - { - ID = id, - DisplayName = name, - CategoryId = categoryId - }); - } - - QuickTicketSelection.ItemsSource = quickCallListe; - - QuickTicketSelection.SelectedItem = quickCallListe - .FirstOrDefault(x => x.ID == "7bbe64e2-94d0-ee11-4285-00155d010a04"); - ValidateProperty(ValidationPropertyNames.QuickTicketSelection); - ApplyQuickCallCategorySelection(); - } - catch (Exception e) - { - LogException(e); - } - } - - public class QuickCallEntry - { - public string ID { get; set; } - public string DisplayName { get; set; } - public Guid? CategoryId { get; set; } - public override string ToString() - { - return DisplayName.ToString(); - } - } - - private void ApplyQuickCallCategorySelection() - { - try - { - if (!NewTicketPillSelected) - return; - - if (!(QuickTicketSelection?.SelectedItem is QuickCallEntry quickCall)) - return; - - if (!quickCall.CategoryId.HasValue || quickCall.CategoryId.Value == Guid.Empty) - return; - - var targetTicket = SelectedTicket ?? _selectTicketRelation; - if (targetTicket.Infos == null) - targetTicket.Infos = new Dictionary(StringComparer.OrdinalIgnoreCase); - - targetTicket.Infos[TicketInfoKeys.Category] = quickCall.CategoryId.Value.ToString(); - - if (ReferenceEquals(targetTicket, SelectedTicket)) - { - TrySelectTicketCategoryFromTicketInfos(); - } - else if (SelectedTicket == null && ReferenceEquals(targetTicket, _selectTicketRelation)) - { - SelectedTicket = targetTicket; - } - } - catch (Exception ex) - { - LogException(ex); - } - } - - - private void UpdateTicketSelection() - { - - try - { - TicketSelectionContainer.Children.Clear(); - - if (DataProvider is null) - return; - - if (!DataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var tempTicketRelations)) - return; - - var ticketRelations = new List(tempTicketRelations); - //ticketRelations.Insert(0, newTicketRelation); - //ticketRelations.Add(noTicketRelation); - - foreach (var ticketRelation in ticketRelations) - { - var tempTicketElement = GetTicketUiElement(ticketRelation); - - if (tempTicketElement is Border ticketBorder) - { - if (ticketRelations.FirstOrDefault() == ticketRelation) - ticketBorder.CornerRadius = new CornerRadius(7.5, 7.5, 0, 0); - else if (ticketRelations.LastOrDefault() == ticketRelation) - ticketBorder.CornerRadius = new CornerRadius(0, 0, 7.5, 7.5); - } - - if (tempTicketElement is null) - continue; - - TicketSelectionContainer.Children.Add(tempTicketElement); - } - - var currentlySelectedTicket = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket); - if (currentlySelectedTicket != null && !NewTicketPillSelected) - SelectedTicket = ticketRelations.FirstOrDefault(ticket => ticket.id == currentlySelectedTicket.Id); - } - catch (Exception E) - { - LogException(E); - } - } - - private void UpdateCaseNotesPreview() - { - try - { - if (DataProvider is null) - return; - - var caseNotesFlowDocument = DataProvider.CaseNotes; - StringBuilder caseNotes = new StringBuilder(); - cRichTextBoxHelper.TraverseBlockAsUnicode(caseNotesFlowDocument.Blocks, caseNotes); - CaseNotesPreview.Text = caseNotes.ToString(); - } - catch (Exception E) - { - LogException(E); - } - - } - private void AddNewOrExistingOrNoneTicketSelection() - { - try - { - bool createTicket = _selectedTicket == null || SelectedTicket == _selectTicketRelation || selectedTicketIsNewTicket; - if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && - Enum.TryParse(statusIdString, true, out enumTicketStatus statusId)) - { - createTicket = statusId == enumTicketStatus.Closed; - SelectedTicket = SelectedTicket ?? _selectTicketRelation; - } - - TicketSelectionBorder.IsEnabled = !createTicket; - - var pillInfos = new (string, string, string, bool, bool)[] - { - ("Header.Create.Ticket", "CreateTicket", "misc_plus", false, createTicket), - ("Header.Select.Ticket", "SelectTicket", "ic_drafts", true, !createTicket), - ("Header.Skip.Ticket", "SkipTicket", "ic_block", true, false) - }; - NewTicketPillSelected = createTicket; - - foreach (var (textKey, tag, icon, isMaterialIcon, isSelected) in pillInfos) - { - var pillText = cMultiLanguageSupport.GetItem(textKey); - var selectionPill = new SelectionPill - { - PillText = pillText, - Tag = tag, - SelectOne = true, - GroupName = "NewUpdateNoTicketSelection", - IsSelected = isSelected - }; - - if (isMaterialIcon) - { - selectionPill.SelectedMaterialIcon = (MaterialIconType)Enum.Parse(typeof(MaterialIconType), icon); - } - else - { - selectionPill.SelectedInternIcon = (enumInternIcons)Enum.Parse(typeof(enumInternIcons), icon); - } - if (checkTicketActive()) - { - if (string.Equals(tag, "SelectTicket", StringComparison.OrdinalIgnoreCase)) - { - selectionPill.IsSelectedChanged += (s, e) => - { - TicketSelectionBorder.IsEnabled = selectionPill.IsSelected; - - - if (!DataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var tempTicketRelations)) - return; - - var ticketRelations = new List(tempTicketRelations); - var currentlySelectedTicket = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket); - SelectedTicket = SelectedTicket ?? ticketRelations.FirstOrDefault(ticket => ticket.id == currentlySelectedTicket.Id); - ValidateProperty(ValidationPropertyNames.SelectedTicket); - ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); - ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); - }; - } - else if (string.Equals(tag, "CreateTicket", StringComparison.OrdinalIgnoreCase)) - { - selectionPill.IsSelectedChanged += (s, e) => - { - NewTicketPillSelected = selectionPill.IsSelected; - SelectedTicket = selectionPill.IsSelected ? SelectedTicket : _selectTicketRelation; - if (selectionPill.IsSelected) - { - SelectedTicket = _selectTicketRelation; - ApplyQuickCallCategorySelection(); - } - ValidateProperty(ValidationPropertyNames.SelectedTicket); - ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); - ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); - }; - } - else if (string.Equals(tag, "SkipTicket", StringComparison.OrdinalIgnoreCase)) - { - selectionPill.IsSelectedChanged += (s, e) => - { - _skipTicketPillSelected = selectionPill.IsSelected; - _errors.Clear(); - UpdateTicketComponentVisibility(); - ValidateProperty(ValidationPropertyNames.SelectedTicket); - ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); - ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); - if (selectionPill.IsSelected) - { - TicketStatusCombobox.SelectedIndex = 0; - } - }; - } - NewOrExistingOrNoneTicketWrap.Children.Add(selectionPill); - } - } - } - catch (Exception E) - { - LogException(E); - } - } - private void AddCopyTemplates() - { - try - { - foreach (var copyTemplate in cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig.CopyTemplates.CopyTemplates) - { - if (copyTemplate.Value.HiddenInTicketDialog) - continue; - - var selectionPill = new SelectionPill() { PillText = copyTemplate.Value.Names.GetValue(), Tag = copyTemplate.Value }; - - if (!string.IsNullOrWhiteSpace(copyTemplate.Value.Descriptions.GetValue())) - selectionPill.ToolTip = copyTemplate.Value.Descriptions.GetValue(); - - switch (copyTemplate.Value.Icon.IconType) - { - case enumIconType.intern: - if (Enum.TryParse(copyTemplate.Value.Icon.Name, out enumInternIcons internIcon)) - selectionPill.SelectedInternIcon = internIcon; - break; - case enumIconType.material: - if (Enum.TryParse(copyTemplate.Value.Icon.Name, out MaterialIcons.MaterialIconType materialIcon)) - selectionPill.SelectedMaterialIcon = materialIcon; - break; - case enumIconType.gif: - if (Enum.TryParse(copyTemplate.Value.Icon.Name, out enumInternGif internGif)) - selectionPill.SelectedGif = internGif; - break; - } - - CopyTemplateWrap.Children.Add(selectionPill); - } - } - catch (Exception E) - { - LogException(E); - } - } - - private string GetCopyText(enumCopyContentFormat format) - { - string output = string.Empty; - - try - { - if (CopyTemplateWrap.Children?.Count <= 0) - return string.Empty; - - foreach (var child in CopyTemplateWrap.Children) - { - if (!(child is SelectionPill selectionPill)) - continue; - - if (selectionPill.IsSelected == false) - continue; - - if (!(selectionPill.Tag is cCopyTemplate selectedCopyTemplate)) - continue; - - if (!selectedCopyTemplate.CopyContentList.TryGetValue(format, out cCopyContent copyContent)) - if (!selectedCopyTemplate.CopyContentList.TryGetValue(enumCopyContentFormat.UNICODE, out copyContent)) - continue; - - if (copyContent is null) - continue; - - if (!string.IsNullOrEmpty(output)) - output += format == enumCopyContentFormat.HTML ? "

" : "\n\n"; - - string copyText = copyContent.Content; - copyText = DataProvider.HealthCardDataHelper.ReplaceNamedParameters(copyText, format == enumCopyContentFormat.HTML); - - if (format == enumCopyContentFormat.HTML) - output += "
" + copyText + "
"; - else - output += copyText; - } - } - catch (Exception E) - { - LogException(E); - } - - return output; - } - - #region CloseCaseWithTicket - - private bool CloseCaseWithCopy() - { - try - { - StringBuilder asciiStringBuilder = new StringBuilder(); - StringBuilder htmlStringBuilder = new StringBuilder(); - - if (TransferCaseNotesCheck.IsChecked ?? false) - { - - var caseNotes = DataProvider.CaseNotes; - - var unicodeCaseNotes = new StringBuilder(); - cRichTextBoxHelper.TraverseBlockAsUnicode(DataProvider.CaseNotes.Blocks, unicodeCaseNotes); - if (!string.IsNullOrWhiteSpace(unicodeCaseNotes.ToString())) - { - asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Summary") + ": \n"); - htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Summary") + ":
"); - asciiStringBuilder.Append(unicodeCaseNotes); - } - - var htmlCaseNotes = new StringBuilder(); - cRichTextBoxHelper.TraverseBlockAsHtml(DataProvider.CaseNotes.Blocks, htmlCaseNotes); - if (!string.IsNullOrWhiteSpace(htmlCaseNotes.ToString())) - htmlStringBuilder.Append(htmlCaseNotes); - else - htmlStringBuilder.Append(unicodeCaseNotes); - } - - if (string.IsNullOrEmpty(asciiStringBuilder.ToString()) is false) - asciiStringBuilder.AppendLine(); - - if (string.IsNullOrEmpty(htmlStringBuilder.ToString()) is false) - htmlStringBuilder.AppendLine("

"); - - - var copyText = GetCopyText(enumCopyContentFormat.UNICODE); - if (!string.IsNullOrEmpty(copyText)) - { - asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.CopyTemplates") + ": \n"); - htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.CopyTemplates") + ":
"); - - asciiStringBuilder.AppendLine(copyText); - htmlStringBuilder.AppendLine(GetCopyText(enumCopyContentFormat.HTML)); - } - - if (TransferQuickActionHistoryCheck.IsChecked ?? false) - { - var quickActionProtocoll = F4SDProtocoll.Instance.GetAllAsDataObject(true); - var actionText = quickActionProtocoll.GetText(); - - if (!string.IsNullOrEmpty(actionText)) - { - - if (string.IsNullOrEmpty(asciiStringBuilder.ToString()) is false) - asciiStringBuilder.AppendLine(); - - if (string.IsNullOrEmpty(htmlStringBuilder.ToString()) is false) - htmlStringBuilder.AppendLine("

"); - - asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.QuickActions") + ": \n"); - htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.QuickActions") + ":

"); - - asciiStringBuilder.AppendLine(quickActionProtocoll.GetText()); - htmlStringBuilder.AppendLine("
" + quickActionProtocoll.GetText(TextDataFormat.Html)); - } - } - - - DataObject tempDataObj = new DataObject(); - tempDataObj.SetText(asciiStringBuilder.ToString()); - tempDataObj.SetText(cUtility.GetHtmlFrame(htmlStringBuilder.ToString()), TextDataFormat.Html); - - System.Windows.Forms.Clipboard.SetDataObject(tempDataObj, true); - - return true; - } - catch (Exception E) - { - LogException(E); - } - - - return false; - } - - private async Task CloseCaseWithTicketAsync(Guid? userId = null) - { - var cm = MethodBase.GetCurrentMethod(); - LogMethodBegin(cm); - - try - { - if (SelectedTicket.Equals(_noTicketRelation)) - return false; - // Update Ticket Tables - const string ticketTable = "M42Wpm-Tickets"; - Dictionary ticketValues = new Dictionary() - { - ["UserId"] = userId, - - ["id"] = SelectedTicket.id, - [TicketInfoKeys.Summary] = TicketSummaryTextBox.Text, - ["CreationSource"] = 3, - ["Status"] = enumTicketStatus.Unknown, - ["time"] = DateTime.UtcNow, - ["Priority"] = 2, - }; - Guid quickcallId = Guid.Empty; - if (QuickTicketSelection.SelectedItem is QuickCallEntry selectedQuickTicketItem) - { - //ticketValues.Add("Category", selectedQuickTicketItem.DisplayName); - ticketValues.Add("QuickCallId", selectedQuickTicketItem.ID); - Guid.TryParse(selectedQuickTicketItem.ID?.ToString(), out quickcallId); - } - var selectedCategoryId = GetSelectedCategoryGuid(); - if (selectedCategoryId.HasValue) - ticketValues[TicketInfoKeys.Category] = selectedCategoryId.Value; - enumCloseCaseTicketStatus? closeCaseTicketStatus = null; - int errorType = -1; - var comment = string.Empty; - DateTime? reminderDate = null; - Guid? selectedRole = null; - Guid? selectedPerson = null; - if (TicketStatusCombobox.SelectedItem is ComboBoxItem selectedItem - && Enum.TryParse(selectedItem.Tag?.ToString(), out enumCloseCaseTicketStatus result)) - { - closeCaseTicketStatus = result; - switch (closeCaseTicketStatus) - { - case enumCloseCaseTicketStatus.Close: - ticketValues.Add("ClosingDate", DateTime.UtcNow); - ticketValues["Status"] = enumTicketStatus.Closed; - - if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicket) - { - ticketValues.Add("Solution", closeTicket.Solution); - if (closeTicket.ErrorTypeComboBox.SelectedItem is ComboBoxItem closeTicketComboBox) - { - int.TryParse(closeTicketComboBox.Tag?.ToString(), out errorType); - ticketValues.Add("ErrorType", closeTicketComboBox.Tag); - } - } - break; - case enumCloseCaseTicketStatus.OnHold: - { - if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicket) - { - comment = holdTicket.Comment; - } - } - ticketValues["Status"] = enumTicketStatus.OnHold; - break; - case enumCloseCaseTicketStatus.Forward: - if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicket) - { - var roleSelection = forwardTicket.RoleSelectionControl.GetSelectedValue(); - if (roleSelection.HasValue) - { - var roleSelectionval = roleSelection.Value.Value.ToString(); - if (Guid.TryParse(roleSelectionval, out var roleResult)) - { - selectedRole = roleResult; - } - } - var personSelection = forwardTicket.PersonSelectionControl.GetSelectedValue(); - if (personSelection.HasValue) - { - var personSelectionval = personSelection.Value.Value.ToString(); - if (Guid.TryParse(personSelectionval, out var personResult)) - { - selectedPerson = personResult; - } - } - comment = forwardTicket.Comment; - } - ticketValues["Status"] = enumTicketStatus.InProgress; - break; - default: - ticketValues["Status"] = enumTicketStatus.New; - break; - } - } - - string user = string.Empty; - if (DataProvider.NamedParameterEntries.TryGetValue("UserFullName", out var userNameParameter)) - user = userNameParameter.GetValue(); - ticketValues.Add("AffectedUser", user); - string asset = string.Empty; - if (SelectedComputer == _removeAffectedAssetEntry) - { - asset = TicketSpecialValues.RemoveAffectedAssetEntry; - } - else if (SetOrUpdateComputerInTicket) - { - asset = SelectedComputer?.DisplayName; - } - - ticketValues.Add("Asset", asset); - - Guid? service = null; - if (SetOrUpdateServiceInTicket && SelectedService.Value != null) - { - if (string.Equals(SelectedService.Value.ToString(), TicketSpecialValues.RemoveAffectedServiceEntry, StringComparison.OrdinalIgnoreCase)) - service = Guid.Empty; - else if (Guid.TryParse(SelectedService.Value.ToString(), out Guid parsedGuid)) - { - service = parsedGuid; - } - } - - - string adDnComputer = string.Empty; - string userFullName = string.Empty; - string userAccount = string.Empty; - string adDnUser = string.Empty; - string userMail = string.Empty; - - // Abrufen der Variablenwerte aus den NamedParameterEntries - if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-computer", out var adDnComputerParameter)) - { - adDnComputer = adDnComputerParameter.GetValue(); - } - - if (DataProvider.NamedParameterEntries.TryGetValue("UserFullName", out var userFullNameParameter)) - { - userFullName = userFullNameParameter.GetValue(); - } - - if (DataProvider.NamedParameterEntries.TryGetValue("UserAccount", out var userAccountParameter)) - { - userAccount = userAccountParameter.GetValue(); - } - - if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-User", out var adDnUserParameter)) - { - adDnUser = adDnUserParameter.GetValue(); - } - - if (DataProvider.NamedParameterEntries.TryGetValue("UserMail", out var userMailParameter)) - { - userMail = userMailParameter.GetValue(); - } - - var htmlCaseNotes = new StringBuilder(); - if (TransferCaseNotesCheck.IsChecked ?? false) - { - var caseNotes = DataProvider.CaseNotes; - - var unicodeCaseNotes = new StringBuilder(); - cRichTextBoxHelper.TraverseBlockAsUnicode(DataProvider.CaseNotes.Blocks, unicodeCaseNotes); - if (!string.IsNullOrWhiteSpace(unicodeCaseNotes.ToString())) - ticketValues.Add("Description", unicodeCaseNotes.ToString()); - - cRichTextBoxHelper.TraverseBlockAsHtml(DataProvider.CaseNotes.Blocks, htmlCaseNotes); - if (!string.IsNullOrWhiteSpace(htmlCaseNotes.ToString())) - ticketValues.Add("DescriptionHtml", htmlCaseNotes.ToString()); - } - - const string journalTable = "M42Wpm-Tickets-History"; - - //Update QuickAction History - string solutionHtmlString = string.Empty; - Dictionary quickActionValues = null; - - if (ticketValues.TryGetValue("Solution", out var solutionValue)) - { - if (solutionValue is string solutionString) - { - if (!string.IsNullOrWhiteSpace(solutionString)) - { - solutionString += "\n\n\n"; - solutionHtmlString = solutionString + "


"; - } - else - { - solutionHtmlString = "


"; - } - - ticketValues["Solution"] = solutionString; - ticketValues["SolutionHtml"] = solutionHtmlString; - } - } - - if (TransferQuickActionHistoryCheck.IsChecked ?? false) - { - var quickActionProtocoll = F4SDProtocoll.Instance.GetAllAsDataObject(true); - - if (ticketValues.TryGetValue("Solution", out solutionValue)) - { - if (solutionValue is string solutionString) - { - solutionString += quickActionProtocoll.GetText(); - solutionHtmlString += quickActionProtocoll.GetText(TextDataFormat.Html); - - ticketValues["Solution"] = solutionString; - ticketValues["SolutionHtml"] = solutionHtmlString; - } - } - else - { - var tempQuickActionValues = new Dictionary() - { - ["UserId"] = userId, - ["id"] = SelectedTicket.id, - ["Header"] = "Commented by F4SD", - ["IsVisibleForUser"] = false, - ["time"] = DateTime.UtcNow, - ["Description"] = quickActionProtocoll.GetText(), - ["DescriptionHtml"] = string.IsNullOrWhiteSpace(quickActionProtocoll.GetText(TextDataFormat.Html)) - ? quickActionProtocoll.GetText() - : quickActionProtocoll.GetText(TextDataFormat.Html) - }; - - if (!string.IsNullOrWhiteSpace(quickActionProtocoll.GetText())) - quickActionValues = tempQuickActionValues; - } - } - - await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = ticketTable, Values = ticketValues }); - - if (quickActionValues != null) - await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = journalTable, Values = quickActionValues }); - - string copyString = GetCopyText(enumCopyContentFormat.UNICODE); - string copyStringHtml = GetCopyText(enumCopyContentFormat.HTML); - if (!string.IsNullOrWhiteSpace(copyString)) - { - Dictionary copyValues = new Dictionary() - { - ["UserId"] = userId, - - ["id"] = SelectedTicket.id, - ["Header"] = "Commented by F4SD", - ["IsVisibleForUser"] = false, - ["time"] = DateTime.UtcNow, - ["Description"] = copyString, - ["DescriptionHtml"] = string.IsNullOrWhiteSpace(copyStringHtml) ? copyString : copyStringHtml - }; - await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = journalTable, Values = copyValues }); - } - - string statusIdValue = null; - if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var value)) - { - statusIdValue = value; - } - - - var workingTimes = TimerView.GetWorkTimes(); - workingTimes.Add("Description", cMultiLanguageSupport.GetItem("Dialog.CloseCase.WorkingTimeEntryDescription")); - var doNotEscalate = false; - var holdTicketReason = 0; - if (this.DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog) - { - reminderDate = new DateTime( - holdTicketDialog.SelectedDate.Year, - holdTicketDialog.SelectedDate.Month, - holdTicketDialog.SelectedDate.Day, - holdTicketDialog.SelectedHour, - holdTicketDialog.SelectedMinute, - 0); - doNotEscalate = (bool)holdTicketDialog.DoNotEscalate.IsChecked; - if (holdTicketDialog.ReasonSelection.SelectedItem is ComboBoxItem sel) - { - if (int.TryParse(sel.Tag.ToString(), out int tmpReasonTag)) - { - holdTicketReason = tmpReasonTag; - } - } - } - cApiM42Ticket ticketData = new cApiM42Ticket() - { - Ticket = _selectedTicket.Identities == null ? Guid.Empty : SelectedTicket.id, - Action = closeCaseTicketStatus.HasValue ? closeCaseTicketStatus : null, - User = adDnUser, - AffectedAsset = asset, - AffectedService = service, - Category = selectedCategoryId, - Summary = TicketSummaryTextBox.Text, - DescriptionHtml = htmlCaseNotes.ToString(), - Quickcall = quickcallId, - CopyTemplates = string.IsNullOrWhiteSpace(copyStringHtml) ? copyString : copyStringHtml, - SolutionHtml = solutionHtmlString, - ErrorType = errorType, - ReminderDate = reminderDate, - DoNotEscalateWhilePaused = doNotEscalate, - Reason = holdTicketReason, - ResponsibleRole = selectedRole, - ResponsiblePerson = selectedPerson, - Comment = comment, - SupportCaseProtocollEntries = TransferQuickActionHistoryCheck.IsChecked ?? false ? F4SDProtocoll.Instance.GetAll().ToList() : null, - workTimes = workingTimes, - StatusIdValue = statusIdValue, - CaseId = DataProvider.CaseId - }; - ticketData.AdditionalValues.Add("IsTicket", IsTicket); - ticketData.AdditionalValues.Add(TicketInfoKeys.ActivityType, GetSelectedTicketInfoOrDefault(TicketInfoKeys.ActivityType)); - ticketData.AdditionalValues.Add("Dialog.CloseCase.AssetNotFoundInMatrix42", cMultiLanguageSupport.GetItem("Dialog.CloseCase.AssetNotFoundInMatrix42")); - ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonText", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonText")); - ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonTextHtml", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonTextHtml")); - var _res = await cFasdCockpitCommunicationBase.Instance.Matrix42TicketFinalization(ticketData); - return true; - } - catch (Exception e) - { - LogException(e); - } - finally - { - LogMethodEnd(cm); - } - return false; - } - - public async Task CloseCaseAsync(Guid? userId = null) - { - try - { - - if (checkTicketActive() && !_skipTicketPillSelected) - return await CloseCaseWithTicketAsync(userId); - else - return CloseCaseWithCopy(); - } - catch (Exception E) - { - LogException(E); - } - - return false; - } - - #endregion - - - public List GetErrors(string propertyName) - { - switch (propertyName) - { - case ValidationPropertyNames.SelectedTicket: - if (SelectedTicket == _selectTicketRelation && !NewTicketPillSelected && !SkipTicketPillSelected) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Header.Select.Ticket")); - } - else - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - break; - case ValidationPropertyNames.TicketSummaryTextBox: - validateTextboxNotEmpty(TicketSummaryTextBox); - if (!string.IsNullOrEmpty(TicketSummaryTextBox.Text) || !TicketSummaryTextBox.IsVisible) - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - else - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorSummaryEmpty")); - } - break; - case ValidationPropertyNames.CaseNotesPreview: - var errorNotEmpty = CheckTextBlockNotEmpty(CaseNotesPreview, cFasdCockpitConfig.Instance.Global.TicketConfiguration.NotesMandatory); - if (errorNotEmpty && CaseNotesPreview.IsVisible) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorCaseNoteEmpty")); - } - else - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - break; - case ValidationPropertyNames.SolutionTextbox: - if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicketDialog) - { - if (string.IsNullOrEmpty(closeTicketDialog.Solution)) - { - setTextboxErrorState(closeTicketDialog.SolutionTextbox, true); - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorSolutionEmpty")); - } - else - { - setTextboxErrorState(closeTicketDialog.SolutionTextbox, false); - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - } - break; - case ValidationPropertyNames.ReminderDate: - if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog) - { - if (holdTicketDialog.SelectedReminderDate <= DateTime.UtcNow.AddMinutes(-2)) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorReminderDate")); - } - else - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - } - break; - - case ValidationPropertyNames.ErrorTypeValue: - if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicketDialog2) - { - if (closeTicketDialog2.SelectedErrorType == null || closeTicketDialog2.SelectedErrorType is ComboBoxItem b && b.Tag == null) - { - closeTicketDialog2.UpdateErrorTypeValidationState(true); - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorTypeEmpty")); - } - else - { - closeTicketDialog2.UpdateErrorTypeValidationState(false); - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - } - break; - - case ValidationPropertyNames.SelectedRoleAndPerson: - if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicketDialog) - { - bool hasError = (forwardTicketDialog.SelectedPerson.Key == null || forwardTicketDialog.SelectedPerson.Value == null) && - (forwardTicketDialog.SelectedRole.Key == null || forwardTicketDialog.SelectedRole.Value == null); - - forwardTicketDialog.UpdateResponsibleSelectionValidationState(hasError); - - if (hasError) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorRoleAndPersonEmpty")); - } - else - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - } - break; - - case ValidationPropertyNames.ForwardComment: - if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicketDialog2) - { - if (string.IsNullOrEmpty(forwardTicketDialog2.Comment)) - { - setTextboxErrorState(forwardTicketDialog2.CommentTextbox, true); - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ForwardTicket.ValidationErrorCommentEmpty")); - } - else - { - setTextboxErrorState(forwardTicketDialog2.CommentTextbox, false); - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - } - break; - case ValidationPropertyNames.HoldComment: - if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog1) - { - if (string.IsNullOrEmpty(holdTicketDialog1.Comment)) - { - setTextboxErrorState(holdTicketDialog1.CommentTextBox, true); - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.HoldTicket.ValidationErrorCommentEmpty")); - } - else - { - setTextboxErrorState(holdTicketDialog1.CommentTextBox, false); - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - } - break; - - case ValidationPropertyNames.TicketStatusCombobox: - if (!(TicketStatusCombobox.SelectedItem is ComboBoxItem a)) - break; - - enumTicketStatus currentTicketStatus = enumTicketStatus.Unknown; - if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && - Enum.TryParse(statusIdString, true, out enumTicketStatus parsedStatus)) - { - currentTicketStatus = parsedStatus; - } - - bool ticketActionHasError = TicketStatusCombobox.IsVisible && a.Tag == null; - if (!ticketActionHasError) - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - else if (!_errors.ContainsKey(propertyName)) - { - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorTicketActionEmpty")); - } - UpdateTicketStatusValidationVisualState(ticketActionHasError); - - if (a.Tag == null) - { - ShowAssetWarningTicketAction = false; - break; - } - - enumCloseCaseTicketStatus? selectedStatus = null; - if (Enum.TryParse(a.Tag.ToString(), true, out enumCloseCaseTicketStatus parsedStatusAction)) - { - selectedStatus = parsedStatusAction; - } - - bool hasTicketActivity = TryGetSelectedTicketInfo(TicketInfoKeys.ActivityType, out var currentTicketActivityType) && - string.Equals(currentTicketActivityType, TicketInfoValues.ActivityTypeTicket, StringComparison.OrdinalIgnoreCase); - - if (selectedStatus.HasValue && selectedStatus != enumCloseCaseTicketStatus.Forward && selectedStatus != enumCloseCaseTicketStatus.Save && hasTicketActivity) - { - ShowAssetWarningTicketAction = true; - var binding = new Binding - { - Converter = _languageConverter, - ConverterParameter = "Dialog.CloseCase.ValidationErrorTicketToIncident" - }; - - WarningTicketAction.SetBinding(ToolTipProperty, binding); - } - else if (currentTicketStatus == enumTicketStatus.Closed) - { - ShowAssetWarningTicketAction = true; - var binding = new Binding - { - Converter = _languageConverter, - ConverterParameter = "Dialog.CloseCase.ValidationErrorTicketWillBeReopened" - }; - - WarningTicketAction.SetBinding(ToolTipProperty, binding); - } - else - { - ShowAssetWarningTicketAction = false; - } - - break; - case ValidationPropertyNames.SelectedCategory: - bool categoryIsVisible = CategorySelectionControl?.IsVisible ?? false; - bool categoryHasError = categoryIsVisible && SelectedCategory == null; - UpdateCategoryValidationVisualState(categoryHasError); - - if (categoryHasError) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorCategoryEmpty")); - } - else - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - - break; - case ValidationPropertyNames.QuickTicketSelection: - bool quickCallIsVisible = QuickTicketSelection?.IsVisible ?? false; - bool quickCallSelected = QuickTicketSelection?.SelectedItem is QuickCallEntry selectedQuickCall && !string.IsNullOrWhiteSpace(selectedQuickCall.ID); - bool quickCallHasError = quickCallIsVisible && !quickCallSelected; - UpdateQuickTicketValidationVisualState(quickCallHasError); - - if (quickCallHasError) - { - if (!_errors.ContainsKey(propertyName)) - _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorQuickCallEmpty")); - } - else - { - if (_errors.ContainsKey(propertyName)) - _errors.Remove(propertyName); - } - - break; - } - - return new List(_errors.Values); - } - - - private void ValidateProperty(string propertyName) - { - var errors = GetErrors(propertyName); - if (errors != null && errors.Count > 0) - { - // Speichern-Button deaktivieren - if (Window.GetWindow(this) is TicketCompletion msgBox) - { - this.parentWindow = msgBox; - this.parentWindow.SetButtonStateYes(false, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorsList") + "\r\n• " + string.Join("\r\n• ", errors)); - } - } - else - { - // Speichern-Button aktivieren - Window parentWindow = Window.GetWindow(this); - - if (parentWindow is TicketCompletion _msgBox) - { - this.parentWindow = _msgBox; - this.parentWindow.SetButtonStateYes(true, ""); - } - } - } - - #region TicketRelation_Click - - private void TicketRelation_Click(object sender) - { - try - { - if (!(sender is FrameworkElement senderElement)) - return; - - if (!(senderElement.Tag is cF4sdApiSearchResultRelation selectedSearchResult)) - return; - - SelectedTicket = selectedSearchResult; - UpdateSelectedTicketControl(); - TicketSelectionPopUp.IsOpen = false; - } - catch (Exception E) - { - LogException(E); - } - } - - private void TicketRelation_TouchDown(object sender, TouchEventArgs e) - { - TicketRelation_Click(sender); - } - - private void TicketRelation_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - TicketRelation_Click(sender); - } - - #endregion - - #region EditCaseNotesButton_Click - - private void EditCaseNotesButton_Click() - { - try - { - if (SupportNotepad == false) - { - return; - } - - - TicketNotepadChanged?.Invoke(this, true); - - //TODO - //var notepad = new Notepad(true, DataProvider.caseNotes) { DataProvider = DataProvider }; - //openedWindows.Add(Window.GetWindow(notepad)); - } - catch (Exception E) - { - LogException(E); - } - - } - - private void EditCaseNotesButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - EditCaseNotesButton_Click(); - - if (!string.IsNullOrWhiteSpace(CaseNotesPreview.Text)) - { - CaseNotesPreviewBorder.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); - ValidateProperty(ValidationPropertyNames.CaseNotesPreview); - } - else - { - CaseNotesPreviewBorder.BorderBrush = SharedValidationBorderBrush; - } - } - - private void EditCaseNotesButton_TouchDown(object sender, TouchEventArgs e) - { - EditCaseNotesButton_Click(); - } - - #endregion - - private void TicketStatusCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - - if (DynamicStatusAdditionBorder is null) - return; - - if (!(sender is ComboBox comboBox)) - return; - - // Die Werte aus 'errors' entfernen - Array.ForEach( - new[] - { - ValidationPropertyNames.SolutionTextbox, - ValidationPropertyNames.ErrorTypeValue, - ValidationPropertyNames.ReminderDate, - ValidationPropertyNames.SelectedRoleAndPerson, - ValidationPropertyNames.ForwardComment, - ValidationPropertyNames.HoldComment - }, - key => _errors.Remove(key)); - ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); - - if (!(comboBox.SelectedItem is ComboBoxItem selectedItem)) - return; - if (!(Enum.TryParse(selectedItem.Tag?.ToString(), out enumCloseCaseTicketStatus closeCaseTicketStatus))) - { - DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed; - return; - } - - FrameworkElement dynamicStatusChild = null; - switch (closeCaseTicketStatus) - { - case enumCloseCaseTicketStatus.Close: - var dialog = new CloseTicketDialog() { DataProvider = DataProvider }; - dialog.ErrorTypeValueChanged += Dialog_ErrorTypeValueChanged; - dialog.SolutionValueChanged += SolutionTextboxValueChanged; - var _h = Dispatcher.BeginInvoke((Action)(() => - { - if (dialog.IsLoaded) - { - ValidateProperty(ValidationPropertyNames.SolutionTextbox); - ValidateProperty(ValidationPropertyNames.ErrorTypeValue); - } - }), System.Windows.Threading.DispatcherPriority.Loaded); - - - dynamicStatusChild = dialog; - break; - case enumCloseCaseTicketStatus.OnHold: - var holdTicketDialog = new HoldTicketDialog(DataProvider = DataProvider); - dynamicStatusChild = holdTicketDialog; - holdTicketDialog.SelectedReminderDateChanged += ReminderDateValueChanged; - holdTicketDialog.CommentChanged += HoldCommentChanged; - _h = Dispatcher.BeginInvoke((Action)(() => - { - if (holdTicketDialog.IsLoaded) - { - ValidateProperty(ValidationPropertyNames.ReminderDate); - ValidateProperty(ValidationPropertyNames.HoldComment); - } - }), System.Windows.Threading.DispatcherPriority.Loaded); - break; - case enumCloseCaseTicketStatus.Forward: - var forwardTicketDialog = new ForwardTicketDialog(DataProvider); - dynamicStatusChild = forwardTicketDialog; - forwardTicketDialog.SelectedPersonChanged += SelectedPersonChanged; - forwardTicketDialog.SelectedRoleChanged += SelectedRoleChanged; - forwardTicketDialog.CommentChanged += ForwardCommentChanged; - _h = Dispatcher.BeginInvoke((Action)(() => - { - if (forwardTicketDialog.IsLoaded) - { - ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); - ValidateProperty(ValidationPropertyNames.ForwardComment); - } - }), System.Windows.Threading.DispatcherPriority.Loaded); - break; - case enumCloseCaseTicketStatus.Save: - break; - } - if (dynamicStatusChild != null) - { - DynamicStatusAdditionBorder.Visibility = Visibility.Visible; - DynamicStatusAdditionBorder.Child = dynamicStatusChild; - } - else - DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed; - this.VerticalAlignment = VerticalAlignment.Center; - } - private void ForwardCommentChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.ForwardComment); - } - private void HoldCommentChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.HoldComment); - } - private void SelectedRoleChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); - } - - private void SelectedPersonChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); - } - - private void ReminderDateValueChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.ReminderDate); - } - private void SolutionTextboxValueChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.SolutionTextbox); - } - - private void Dialog_ErrorTypeValueChanged(object sender, EventArgs e) - { - ValidateProperty(ValidationPropertyNames.ErrorTypeValue); - } - - private void TicketSelectionBorder_Click() - { - var _h = Dispatcher.Invoke(async () => - { - await Task.Delay(50); - - if (!TicketSelectionPopUp.IsOpen) - DropDownOpened(TicketSelectionBorder, EventArgs.Empty); - - TicketSelectionPopUp.IsOpen = !TicketSelectionPopUp.IsOpen; - }); - } - - private void TicketSelectionBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) - { - TicketSelectionBorder_Click(); - } - - private void TicketSelectionBorder_TouchDown(object sender, TouchEventArgs e) - { - TicketSelectionBorder_Click(); - } - - private void TicketSummaryTextBox_TextChanged(object sender, TextChangedEventArgs e) - { - try - { - if (SelectedTicket?.Infos is null) - return; - - SelectedTicket.Infos[TicketInfoKeys.Summary] = TicketSummaryTextBox.Text; - ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); - } - catch (Exception E) - { - LogException(E); - } - - } - - private void TicketCaseNotesTextBlock_TextChanged(object sender, EventArgs e) - { - try - { - if (SelectedTicket?.Infos is null) - return; - - if (string.IsNullOrWhiteSpace(CaseNotesPreview.Text)) - CaseNotesPreview.Text = string.Empty; - - ValidateProperty(ValidationPropertyNames.CaseNotesPreview); - } - catch (Exception E) - { - LogException(E); - } - } - - private static void validateTextboxNotEmpty(object sender) - { - if (sender is TextBox textBox) - { - // Text aus der TextBox holen - string text = textBox.Text; - - // Überprüfe den Inhalt und setze die Hintergrundfarbe entsprechend - if (string.IsNullOrWhiteSpace(text)) - { - // Setze die Hintergrundfarbe auf Rot, um einen Validierungsfehler anzuzeigen - textBox.BorderBrush = SharedValidationBorderBrush; - } - else - { - // Setze die ursprüngliche Hintergrundfarbe zurück, wenn die Validierung erfolgreich ist - textBox.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); - } - } - } - - - private bool CheckTextBlockNotEmpty(TextBlock _textBlock, bool notEmpty) - { - var _retVal = false; - Brush _borderCaseNores = DefaultTextBoxBorderBrush; - if (notEmpty && string.IsNullOrWhiteSpace(_textBlock.Text)) - { - _retVal = true; - _borderCaseNores = SharedValidationBorderBrush; - } - CaseNotesPreviewBorder.BorderBrush = _borderCaseNores; - return _retVal; - } - - - private static void setTextboxErrorState(object sender, bool hasError) - { - if (!(sender is TextBox textBox)) - return; - - textBox.BorderBrush = hasError ? SharedValidationBorderBrush : DefaultTextBoxBorderBrush; - } - - private void UpdateCategoryValidationVisualState(bool hasError) => - UpdateValidationBorderState(CategoryValidationBorder, ref defaultCategoryBorderBrush, ref defaultCategoryBorderThickness, hasError); - - private void UpdateQuickTicketValidationVisualState(bool hasError) => - UpdateValidationBorderState(QuickTicketValidationBorder, ref defaultQuickTicketBorderBrush, ref defaultQuickTicketBorderThickness, hasError); - - private void UpdateTicketStatusValidationVisualState(bool hasError) => - UpdateValidationBorderState(TicketStatusValidationBorder, ref defaultTicketStatusBorderBrush, ref defaultTicketStatusBorderThickness, hasError); - - private void UpdateValidationBorderState(Border border, ref Brush defaultBrush, ref Thickness? defaultThickness, bool hasError) - { - if (border == null) - return; - - if (defaultBrush == null) - { - var borderBrush = border.BorderBrush; - defaultBrush = borderBrush?.CloneCurrentValue(); - } - - if (!defaultThickness.HasValue) - defaultThickness = border.BorderThickness; - - border.BorderBrush = hasError ? validationErrorBrush : defaultBrush; - border.BorderThickness = hasError ? new Thickness(1) : defaultThickness ?? new Thickness(0); - } - - - - #region DropDown - private static bool IsInsidePageable(FrameworkElement fe) => cUiElementHelper.GetFirstParentOfType(fe) != null; - - private void DropDownOpened(object sender, EventArgs e) - { - if (!(sender is FrameworkElement fe)) return; - if (IsInsidePageable(fe)) return; // ComboBoxPageable fired itself - - var parentBorder = cUiElementHelper.GetFirstParentOfType(fe); - if (parentBorder != null) - cFocusInvoker.InvokeGotFocus(parentBorder, e); - } - - private void RestoreDialogFocusAfterTicketActionSelection() - { - try - { - if (DialogContentScrollViewer == null) - return; - - Keyboard.ClearFocus(); - DialogContentScrollViewer.Focus(); - Keyboard.Focus(DialogContentScrollViewer); - } - catch (Exception E) - { - LogException(E); - } - } - - public void SetDialogContentMaxHeight(double maxHeight) - { - try - { - if (DialogContentScrollViewer == null) - return; - - // Keep dialog usable on very small screens; parent window already constrains max size. - DialogContentScrollViewer.MaxHeight = Math.Max(MinDialogContentHeightDip, maxHeight); - } - catch (Exception E) - { - LogException(E); - } - } - - private void DropDownClosed(object sender, EventArgs e) - { - if (!(sender is FrameworkElement fe)) return; - if (IsInsidePageable(fe)) return; - - var parentBorder = cUiElementHelper.GetFirstParentOfType(fe); - if (parentBorder != null) - cFocusInvoker.InvokeLostFocus(parentBorder, e); - - _ = Dispatcher.BeginInvoke(new Action(RestoreDialogFocusAfterTicketActionSelection), System.Windows.Threading.DispatcherPriority.Input); - } - - #endregion - - private void TicketSelectionPopUp_Closed(object sender, EventArgs e) - { - DropDownClosed(TicketSelectionBorder, e); - } - - private void TransferCaseNotesCheck_Checked(object sender, RoutedEventArgs e) - { - try - { - CaseNotesPreview?.ClearValue(OpacityProperty); - CaseNotesPreviewBorder?.ClearValue(IsHitTestVisibleProperty); - } - catch (Exception E) - { - LogException(E); - } - - } - private void ComputerSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - SelectedComputer = (cF4sdApiSearchResultRelation)ComputerSelection.SelectedItem; - } - - private void QuickTicketSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - ValidateProperty(ValidationPropertyNames.QuickTicketSelection); - ApplyQuickCallCategorySelection(); - } - - private void TransferCaseNotesCheck_Unchecked(object sender, RoutedEventArgs e) - { - try - { - if (CaseNotesPreview != null) - CaseNotesPreview.Opacity = 0.7; - - if (CaseNotesPreviewBorder != null) - CaseNotesPreviewBorder.IsHitTestVisible = false; - } - catch (Exception E) - { - LogException(E); - } - - } - - private void CloseCaseDialogUc_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) - { - try - { - if (!(e.NewValue is bool isVisible && !isVisible)) - return; - - foreach (Window window in _openedWindows) - { - if (window is null) - continue; - - window.Close(); - } - } - catch (Exception E) - { - LogException(E); - } - - } - - private void Combobox_PreviewKeyDown(object sender, KeyEventArgs e) - { - if (e.Key == Key.Escape) - { - if (sender is FrameworkElement fe && IsInsidePageable(fe)) return; - DropDownClosed(sender, e); - } - } - } -} +using C4IT.FASD.Base; +using C4IT.FASD.Cockpit.Communication; +using C4IT.MultiLanguage; +using F4SD_AdaptableIcon.Enums; +using FasdDesktopUi.Basics.Helper; +using FasdDesktopUi.Basics.Models; +using FasdDesktopUi.Basics.Services.ProtocollService; +using FasdDesktopUi.Pages.TicketCompletion; +using MaterialIcons; +using System; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Reflection; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Input; +using System.Windows.Media; +using static C4IT.Logging.cLogManager; + +namespace FasdDesktopUi.Basics.UserControls +{ + public partial class CloseCaseDialogWithTicket : UserControl + { + private const double MinDialogContentHeightDip = 220d; + + #region Fields & Properties + private readonly Dictionary _errors = new Dictionary(); + + private readonly IValueConverter _languageConverter = new Converter.LanguageDefinitionsConverter(); + + private readonly List _openedWindows = new List(); + + private readonly cF4sdApiSearchResultRelation _newTicketRelation = new cF4sdApiSearchResultRelation() + { + id = Guid.NewGuid(), + DisplayName = cMultiLanguageSupport.GetItem("Header.Create.Ticket"), + Type = enumF4sdSearchResultClass.Ticket, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.TicketCreation } + }; + + private readonly cF4sdApiSearchResultRelation _selectTicketRelation = new cF4sdApiSearchResultRelation() + { + id = Guid.NewGuid(), + DisplayName = cMultiLanguageSupport.GetItem("Header.Select.Ticket"), + Type = enumF4sdSearchResultClass.Ticket, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.TicketSelect } + }; + + private readonly cF4sdApiSearchResultRelation _noTicketRelation = new cF4sdApiSearchResultRelation() + { + DisplayName = cMultiLanguageSupport.GetItem("Header.Skip.Ticket"), + Type = enumF4sdSearchResultClass.Ticket, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.NoTicket } + }; + + private readonly cF4sdApiSearchResultRelation _removeAffectedAssetEntry = new cF4sdApiSearchResultRelation() + { + DisplayName = cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedAssetEntry"), + Type = enumF4sdSearchResultClass.Computer, + Identities = null, + Infos = new Dictionary { [TicketInfoKeys.Special] = TicketSpecialValues.RemoveAffectedAssetEntry } + }; + + private const string CategoryTableNamePrimary = "M42Wpm-Ticket-Categories"; + private const string TicketDetailsTableName = "M42Wpm-Tickets"; + private const string TicketDetailsCategoryIdColumnName = "CategoryId"; + + private static readonly Brush SharedValidationBorderBrush = CreateValidationBrush(); + private static readonly Brush DefaultTextBoxBorderBrush = CreateDefaultTextBoxBorderBrush(); + private static Brush CreateValidationBrush() + { + var brush = new SolidColorBrush(Color.FromRgb(0xF5, 0x7C, 0x73)); + if (brush.CanFreeze) + brush.Freeze(); + return brush; + } + private static Brush CreateDefaultTextBoxBorderBrush() + { + var brush = new SolidColorBrush(Color.FromRgb(0xDE, 0xE2, 0xE6)); + if (brush.CanFreeze) + brush.Freeze(); + return brush; + } + + private ObservableCollection categoryHierarchy = new ObservableCollection(); + private readonly Dictionary categoryLookup = new Dictionary(StringComparer.OrdinalIgnoreCase); + private bool isCategoryLoading; + private Brush defaultCategoryBorderBrush; + private Brush defaultQuickTicketBorderBrush; + private readonly Brush validationErrorBrush = SharedValidationBorderBrush; + private Brush defaultTicketStatusBorderBrush; + private Thickness? defaultCategoryBorderThickness; + private Thickness? defaultQuickTicketBorderThickness; + private Thickness? defaultTicketStatusBorderThickness; + + public bool AreCaseNotesMandatory => + cFasdCockpitConfig.Instance?.Global?.TicketConfiguration?.NotesMandatory ?? false; + + private static class TicketInfoKeys + { + public const string ActivityType = "ActivityType"; + public const string Asset = "Asset"; + public const string ServiceId = "ServiceId"; + public const string ServiceName = "ServiceName"; + public const string StatusId = "StatusId"; + public const string Category = "Category"; + public const string Summary = "Summary"; + public const string Special = "Special"; + } + + private static class TicketInfoValues + { + public const string ActivityTypeTicket = "SPSActivityTypeTicket"; + } + + private static class TicketSpecialValues + { + public const string TicketCreation = "TicketCreation"; + public const string TicketSelect = "TicketSelect"; + public const string NoTicket = "NoTicket"; + public const string RemoveAffectedAssetEntry = "RemoveAffectedAssetEntry"; + public const string RemoveAffectedServiceEntry = "RemoveAffectedServiceEntry"; + } + + private static class ValidationPropertyNames + { + public const string SelectedTicket = nameof(SelectedTicket); + public const string SelectedCategory = nameof(SelectedCategory); + public const string QuickTicketSelection = nameof(QuickTicketSelection); + public const string TicketSummaryTextBox = nameof(TicketSummaryTextBox); + public const string TicketStatusCombobox = nameof(TicketStatusCombobox); + public const string CaseNotesPreview = nameof(CaseNotesPreview); + public const string SolutionTextbox = "SolutionTextbox"; + public const string ErrorTypeValue = "ErrorTypeValue"; + public const string ReminderDate = "ReminderDate"; + public const string HoldComment = "HoldComment"; + public const string SelectedRoleAndPerson = "SelectedRoleAndPerson"; + public const string ForwardComment = "ForwardComment"; + } + + private bool TryGetSelectedTicketInfo(string key, out string value) + { + value = null; + return SelectedTicket?.Infos != null && SelectedTicket.Infos.TryGetValue(key, out value); + } + + private string GetSelectedTicketInfoOrDefault(string key) => + TryGetSelectedTicketInfo(key, out var value) ? value : null; + + private static bool TryGetSpecialValue(cF4sdApiSearchResultRelation relation, out string specialValue) + { + specialValue = null; + return relation?.Infos != null && relation.Infos.TryGetValue(TicketInfoKeys.Special, out specialValue); + } + + private static bool RelationHasSpecialInfo(cF4sdApiSearchResultRelation relation, string expectedSpecialValue) => + TryGetSpecialValue(relation, out var specialValue) && + string.Equals(specialValue, expectedSpecialValue, StringComparison.OrdinalIgnoreCase); + + public bool IsTicket + { + get + { + return TryGetSelectedTicketInfo(TicketInfoKeys.ActivityType, out var activityType) + && string.Equals(activityType, TicketInfoValues.ActivityTypeTicket, StringComparison.OrdinalIgnoreCase); + } + } + + private bool _isTicketIntegrationActive; + public bool IsTicketIntegrationActive + { + get => _isTicketIntegrationActive; + private set => _isTicketIntegrationActive = value; + } + + public bool EnableHoldTicketAction + { + get { return (bool)GetValue(EnableHoldTicketActionProperty); } + set { SetValue(EnableHoldTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableHoldTicketActionProperty = + DependencyProperty.Register("EnableHoldTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + public bool EnableCloseTicketAction + { + get { return (bool)GetValue(EnableCloseTicketActionProperty); } + set { SetValue(EnableCloseTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableCloseTicketActionProperty = + DependencyProperty.Register("EnableCloseTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + public bool EnableSaveTicketAction + { + get { return (bool)GetValue(EnableSaveTicketActionProperty); } + set { SetValue(EnableSaveTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableSaveTicketActionProperty = + DependencyProperty.Register("EnableSaveTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + public bool EnableForwardTicketAction + { + get { return (bool)GetValue(EnableForwardTicketActionProperty); } + set { SetValue(EnableForwardTicketActionProperty, value); } + } + + public static readonly DependencyProperty EnableForwardTicketActionProperty = + DependencyProperty.Register("EnableForwardTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true)); + + private cF4sdApiSearchResultRelation _selectedTicket; + + public cF4sdApiSearchResultRelation SelectedTicket + { + get => _selectedTicket; + set + { + _selectedTicket = value; + //SelectedComputer = null; + + UpdateSelectedTicketControl(); + CheckAffectedAssetIsCurrentAsset(); + CheckAffectedServiceIsCurrentService(); + UpdateAffectedAssetLabel(); + UpdateAffectedServiceLabel(); + UpdateAffectedAssetComboBox(); + ShowAssetWarningTicketAction = IsTicket; + ValidateProperty(ValidationPropertyNames.SelectedTicket); + EnableHoldTicketAction = _selectedTicket == null || SelectedTicket == _selectTicketRelation || selectedTicketIsNewTicket; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && + Enum.TryParse(statusIdString, true, out enumTicketStatus statusId)) + { + EnableHoldTicketAction = statusId != enumTicketStatus.OnHold; + } + TrySelectTicketCategoryFromTicketInfos(); + _ = EnsureSelectedTicketCategoryFromDetailsAsync(_selectedTicket); + } + } + + private bool selectedTicketIsNewTicket + { + get => SelectedTicket == _newTicketRelation; + } + + #region SelectedComputer DependencyProperty + public static readonly DependencyProperty SelectedComputerProperty = + DependencyProperty.Register("SelectedComputer", typeof(cF4sdApiSearchResultRelation), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(null)); + + public cF4sdApiSearchResultRelation SelectedComputer + { + get { return (cF4sdApiSearchResultRelation)GetValue(SelectedComputerProperty); } + set + { + SetValue(SelectedComputerProperty, value); + CheckAffectedAssetIsCurrentAsset(); + } + } + #endregion + + public bool ShowAssetWarningTicketAction + { + get { return (bool)GetValue(ShowAssetWarningTicketActionProperty); } + set { SetValue(ShowAssetWarningTicketActionProperty, value); } + } + + public static readonly DependencyProperty ShowAssetWarningTicketActionProperty = + DependencyProperty.Register("ShowAssetWarningTicketAction", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); + + #region SelectedService DependencyProperty + + public static readonly DependencyProperty SelectedServiceProperty = DependencyProperty.Register( + "SelectedService", + typeof(KeyValuePair), + typeof(CloseCaseDialogWithTicket), + new PropertyMetadata(default(KeyValuePair), OnSelectedServiceChanged)); + + public KeyValuePair SelectedService + { + get { return (KeyValuePair)GetValue(SelectedServiceProperty); } + set + { + SetValue(SelectedServiceProperty, value); + CheckAffectedServiceIsCurrentService(); + } + } + private static void OnSelectedServiceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var control = (CloseCaseDialogWithTicket)d; + var newValue = (KeyValuePair)e.NewValue; + control.CheckAffectedServiceIsCurrentService(); + } + #endregion + + #region SelectedCategory DependencyProperty + + public static readonly DependencyProperty SelectedCategoryProperty = DependencyProperty.Register( + "SelectedCategory", + typeof(HierarchicalSelectionItem), + typeof(CloseCaseDialogWithTicket), + new PropertyMetadata(null, OnSelectedCategoryChanged)); + + public HierarchicalSelectionItem SelectedCategory + { + get { return (HierarchicalSelectionItem)GetValue(SelectedCategoryProperty); } + set { SetValue(SelectedCategoryProperty, value); } + } + + private static void OnSelectedCategoryChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + { + instance.LogSelectedCategoryChanged(e.NewValue as HierarchicalSelectionItem); + instance.ValidateProperty(ValidationPropertyNames.SelectedCategory); + } + } + + #endregion + + private void LogSelectedCategoryChanged(HierarchicalSelectionItem category) + { + try + { + var fullPath = category == null + ? "" + : string.IsNullOrWhiteSpace(category.FullPath) ? category.DisplayName : category.FullPath; + var id = category == null || string.IsNullOrWhiteSpace(category.Id) ? "" : category.Id; + LogEntry($"[CloseCaseDialog] SelectedCategory updated -> {fullPath} (Id={id})"); + } + catch (Exception ex) + { + LogException(ex); + } + } + + public bool ShowServiceHasBeenChangedWarning + { + get { return ServiceHasBeenChanged && SetOrUpdateServiceInTicket; } + } + public bool ShowAssetHasBeenChangedWarning + { + get { return AssetHasBeenChanged && SetOrUpdateComputerInTicket; } + } + + #region AssetHasBeenChanged DependencyProperty + + public static readonly DependencyProperty AssetHasBeenChangedProperty = + DependencyProperty.Register("AssetHasBeenChanged", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); + + public bool AssetHasBeenChanged + { + get { return (bool)GetValue(AssetHasBeenChangedProperty); } + set { SetValue(AssetHasBeenChangedProperty, value); } + } + + #endregion + + #region SetOrUpdateComputerInTicket DependencyProperty + + public static readonly DependencyProperty SetOrUpdateComputerInTicketProperty = + DependencyProperty.Register("SetOrUpdateComputerInTicket", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(true, OnSetOrUpdateComputerInTicketChanged)); + + private static void OnSetOrUpdateComputerInTicketChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + instance.CheckAffectedAssetIsCurrentAsset(); + } + + public bool SetOrUpdateComputerInTicket + { + get { return (bool)GetValue(SetOrUpdateComputerInTicketProperty); } + set { SetValue(SetOrUpdateComputerInTicketProperty, value); } + } + + #endregion + + private bool _skipTicketPillSelected; + + public bool SkipTicketPillSelected + { + get { return _skipTicketPillSelected; } + set { _skipTicketPillSelected = value; } + } + + private bool _newTicketPillSelected; + + public bool NewTicketPillSelected + { + get { return _newTicketPillSelected; } + set + { + _newTicketPillSelected = value; + ValidateProperty(ValidationPropertyNames.SelectedTicket); + + } + } + + #region SetOrUpdateServiceInTicket DependencyProperty + + public static readonly DependencyProperty SetOrUpdateServiceInTicketProperty = + DependencyProperty.Register("SetOrUpdateServiceInTicket", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false, OnSetOrUpdateServiceInTicketChanged)); + + private static void OnSetOrUpdateServiceInTicketChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + instance.CheckAffectedServiceIsCurrentService(); + } + + public bool SetOrUpdateServiceInTicket + { + get { return (bool)GetValue(SetOrUpdateServiceInTicketProperty); } + set { SetValue(SetOrUpdateServiceInTicketProperty, value); } + } + #endregion + + #region ServiceHasBeenChanged DependencyProperty + + public static readonly DependencyProperty ServiceHasBeenChangedProperty = + DependencyProperty.Register("ServiceHasBeenChanged", typeof(bool), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(false)); + + public bool ServiceHasBeenChanged + { + get { return (bool)GetValue(ServiceHasBeenChangedProperty); } + set { SetValue(ServiceHasBeenChangedProperty, value); } + } + + #endregion + + public static readonly DependencyProperty ComputerRelationsProperty = + DependencyProperty.Register("ComputerRelations", typeof(List), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(new List(), OnComputerRelationsChanged)); + + private static void OnComputerRelationsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is CloseCaseDialogWithTicket instance) + { + //instance.CheckAffectedAssetIsCurrentAsset(); + } + } + + public List ComputerRelations + { + get { return (List)GetValue(ComputerRelationsProperty); } + set { SetValue(ComputerRelationsProperty, value); } + } + + public bool SupportNotepad { get; private set; } = false; + + public static EventHandler TicketNotepadChanged { get; set; } + + #region DataProvider + + public cSupportCaseDataProvider DataProvider + { + get { return (cSupportCaseDataProvider)GetValue(DataProviderProperty); } + set { SetValue(DataProviderProperty, value); } + } + + public static readonly DependencyProperty DataProviderProperty = + DependencyProperty.Register("DataProvider", typeof(cSupportCaseDataProvider), typeof(CloseCaseDialogWithTicket), new PropertyMetadata(null, DataProviderChanged)); + + private static async void DataProviderChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + try + { + if (!(d is CloseCaseDialogWithTicket me)) + return; + + + me.SelectedTicket = me.SelectedTicket ?? me._selectTicketRelation; + + me.UpdateSelectedTicketControl(); + me.UpdateTicketSelection(); + + me.AddCopyTemplates(); + me.UpdateAffectedAssetLabel(); + me.UpdateAffectedServiceLabel(); + me.UpdateAffectedAssetComboBox(); + + me.ServiceSelectionControl.SearchDataChanged = me.HandleServiceSearchDataChanged; + me.ServiceSelectionControl.ParentElement = me.MainStack; + me.ServiceSelectionControl.ParentIndex = me.MainStack.Children.IndexOf(me.ServiceSelectionControl); + + me.AddNewOrExistingOrNoneTicketSelection(); + me.UpdateCaseNotesPreview(); + me.UpdateTicketComponentVisibility(); + await me.InitializeCategorySelectionAsync(); + await me.UpdateQuickCallsComboBoxAsync(); + me.ValidateProperty(ValidationPropertyNames.SelectedCategory); + me.ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + } + catch (Exception E) + { + LogException(E); + } + + } + + #endregion + + #endregion + string lastServiceSearch = string.Empty; + + private TicketCompletion parentWindow; + + public CloseCaseDialogWithTicket() + { + InitializeComponent(); + this.Unloaded += CloseCaseDialogWithTicket_Unloaded; + this.Loaded += CloseCaseDialogWithTicket_Loaded; + defaultCategoryBorderBrush = CategoryValidationBorder?.BorderBrush?.CloneCurrentValue(); + defaultQuickTicketBorderBrush = QuickTicketValidationBorder?.BorderBrush?.CloneCurrentValue(); + defaultTicketStatusBorderBrush = TicketStatusValidationBorder?.BorderBrush?.CloneCurrentValue(); + if (validationErrorBrush is Freezable freezableBrush && freezableBrush.CanFreeze) + freezableBrush.Freeze(); + + DependencyPropertyDescriptor dpd = + DependencyPropertyDescriptor.FromProperty(TextBlock.TextProperty, typeof(TextBlock)); + + dpd?.AddValueChanged(CaseNotesPreview, TicketCaseNotesTextBlock_TextChanged); + + SupportNotepad = true; + } + + private void CloseCaseDialogWithTicket_Loaded(object sender, RoutedEventArgs e) + { + Window _parentWindow = Window.GetWindow(this); + + if (!(_parentWindow is TicketCompletion _msgBox)) + return; + + _parentWindow.Closing += ParentWindow_Closing; + parentWindow = _msgBox; + parentWindow.SetButtonStateYes(false, "Initial gesperrt."); + parentWindow.SetButtonStateNo(true, cMultiLanguageSupport.GetItem("Dialog.CloseCase.Cancel")); + + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + ValidateProperty(ValidationPropertyNames.CaseNotesPreview); + ValidateProperty(ValidationPropertyNames.SelectedCategory); + ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + } + private void CloseCaseDialogWithTicket_Unloaded(object sender, RoutedEventArgs e) + { + Window parentWindow = Window.GetWindow(this); + if (parentWindow != null) + { + parentWindow.Closing -= ParentWindow_Closing; + } + } + private void ParentWindow_Closing(object sender, CancelEventArgs e) + { + foreach (SelectionPill pill in NewOrExistingOrNoneTicketWrap.Children.OfType()) + { + SelectionPill.RemovePill(pill); + } + foreach (SelectionPill pill in CopyTemplateWrap.Children.OfType()) + { + SelectionPill.RemovePill(pill); + } + } + protected override void OnInitialized(EventArgs e) + { + try + { + base.OnInitialized(e); + IsTicketIntegrationActive = cFasdCockpitCommunicationBase.CockpitUserInfo?.Roles?.Any(role => string.Equals(role, "Cockpit.TicketAgent", StringComparison.OrdinalIgnoreCase)) ?? false; + cSupportCaseDataProvider.CaseNotesChanged += (sender, args) => UpdateCaseNotesPreview(); + } + catch (Exception E) + { + LogException(E); + } + } + + + + private void UpdateAffectedAssetLabel() + { + var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); + + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = NewTicketPillSelected || string.IsNullOrEmpty(computerName) ? "Dialog.CloseCase.SetAffectedAssetLabel" : "Dialog.CloseCase.UpdateAffectedAssetLabel" + }; + + SetOrUpdateComputerInTicketLabel.SetBinding(TextBlock.TextProperty, binding); + } + private void UpdateAffectedServiceLabel() + { + var serviceId = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); + + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = NewTicketPillSelected || string.IsNullOrEmpty(serviceId) || serviceId == Guid.Empty.ToString() ? "Dialog.CloseCase.SetAffectedServiceLabel" : "Dialog.CloseCase.UpdateAffectedServiceLabel" + }; + + SetOrUpdateServiceInTicketLabel.SetBinding(TextBlock.TextProperty, binding); + } + + private bool checkTicketActive() + { + var _retVal = IsTicketIntegrationActive; + if (cFasdCockpitCommunicationBase.Instance.IsDemo()) + _retVal = DataProvider.HealthCardDataHelper?.HealthCardRawData?.Tables?.ContainsKey("M42Wpm-User-NewTicket") ?? false; + return _retVal; + } + + private void UpdateTicketComponentVisibility() + { + try + { + if (DataProvider is null) + return; + + var _isVisible = checkTicketActive() && !_skipTicketPillSelected; + + TicketSelectionCategory.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed; + StatusSelectionBorder.Visibility = _isVisible ? Visibility.Visible : Visibility.Collapsed; + CopyDisclaimerTextBox.Visibility = _isVisible ? Visibility.Collapsed : Visibility.Visible; + } + catch (Exception E) + { + LogException(E); + } + } + + private UIElement GetTicketUiElement(cF4sdApiSearchResultRelation ticketRelation) + { + try + { + Border outputBorder = new Border(); + outputBorder.MouseLeftButtonUp += TicketRelation_MouseLeftButtonUp; + outputBorder.TouchDown += TicketRelation_TouchDown; + + outputBorder.SetResourceReference(StyleProperty, "Menu.SubCategory"); + outputBorder.Tag = ticketRelation; + + Grid contentGrid = new Grid(); + outputBorder.Child = contentGrid; + contentGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Auto) }); + contentGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(1, GridUnitType.Star) }); + + AdaptableIcon.AdaptableIcon ticketIcon = new AdaptableIcon.AdaptableIcon() { SelectedInternIcon = enumInternIcons.f4sd_outline }; + + if (RelationHasSpecialInfo(ticketRelation, TicketSpecialValues.TicketCreation)) + { + ticketIcon.SelectedInternIcon = enumInternIcons.misc_plus; + } + else if (RelationHasSpecialInfo(ticketRelation, TicketSpecialValues.NoTicket)) + { + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_block; + } + else if (ticketRelation.Infos.TryGetValue(TicketInfoKeys.StatusId, out string ticketStatusId)) + { + Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus); + + switch (ticketStatus) + { + case enumTicketStatus.New: + case enumTicketStatus.InProgress: + case enumTicketStatus.OnHold: + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts; + break; + case enumTicketStatus.Closed: + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + break; + } + } + else + { + ticketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + } + + contentGrid.Children.Add(ticketIcon); + StackPanel ticketTextStack = new StackPanel() { Margin = new Thickness(15, 0, 15, 0), VerticalAlignment = VerticalAlignment.Center, IsHitTestVisible = false }; + Grid.SetColumn(ticketTextStack, 1); + contentGrid.Children.Add(ticketTextStack); + + Border ticketNameBorder = new Border() { ClipToBounds = true }; + ticketTextStack.Children.Add(ticketNameBorder); + + TextBlock ticketNameTextBlock = new TextBlock() { Text = ticketRelation.DisplayName, TextTrimming = TextTrimming.CharacterEllipsis }; + ticketNameBorder.Child = ticketNameTextBlock; + + Border ticketDescriptionBorder = new Border() { ClipToBounds = true }; + ticketTextStack.Children.Add(ticketDescriptionBorder); + + TextBlock ticketDescriptionTextBlock = null; + if (ticketRelation.Infos.TryGetValue(TicketInfoKeys.Summary, out string ticketSummary)) + { + ticketDescriptionTextBlock = new TextBlock() { Text = ticketSummary, TextTrimming = TextTrimming.CharacterEllipsis, FontWeight = FontWeights.UltraLight }; + ticketDescriptionBorder.Child = ticketDescriptionTextBlock; + } + + outputBorder.MouseEnter += (sender, e) => + { + try + { + cUtility.SetTickerTextAnimation(ticketNameTextBlock, ticketNameBorder); + + if (ticketDescriptionTextBlock != null) + cUtility.SetTickerTextAnimation(ticketDescriptionTextBlock, ticketDescriptionBorder); + } + catch (Exception E) + { + LogException(E); + } + }; + outputBorder.MouseLeave += (sender, e) => + { + try + { + ticketNameTextBlock.TextTrimming = TextTrimming.CharacterEllipsis; + ticketNameTextBlock.BeginAnimation(MarginProperty, null); + + ticketNameBorder.ClearValue(WidthProperty); + ticketNameTextBlock.ClearValue(WidthProperty); + + if (ticketDescriptionTextBlock != null) + { + ticketDescriptionTextBlock.TextTrimming = TextTrimming.CharacterEllipsis; + ticketDescriptionTextBlock.BeginAnimation(MarginProperty, null); + } + } + catch (Exception E) + { + LogException(E); + } + }; + + + return outputBorder; + } + catch (Exception E) + { + LogException(E); + } + + return null; + } + + private void UpdateSelectedTicketControl() + { + try + { + if (SelectedTicket is null) + return; + + TicketIcon.SelectedInternIcon = null; + TicketIcon.SelectedMaterialIcon = null; + TicketTextBlock.Text = SelectedTicket.DisplayName; + + if (SelectedTicket.Infos.TryGetValue(TicketInfoKeys.Summary, out var ticketSummary)) + TicketSummaryTextBox.Text = ticketSummary; + else + TicketSummaryTextBox.Text = string.Empty; + + if (RelationHasSpecialInfo(SelectedTicket, TicketSpecialValues.TicketCreation)) + { + TicketIcon.SelectedInternIcon = enumInternIcons.misc_plus; + } + else if (RelationHasSpecialInfo(SelectedTicket, TicketSpecialValues.NoTicket)) + { + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_block; + } + else if (SelectedTicket.Infos.TryGetValue(TicketInfoKeys.StatusId, out string ticketStatusId)) + { + Enum.TryParse(ticketStatusId, true, out enumTicketStatus ticketStatus); + + switch (ticketStatus) + { + case enumTicketStatus.New: + case enumTicketStatus.InProgress: + case enumTicketStatus.OnHold: + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_drafts; + break; + case enumTicketStatus.Closed: + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + break; + } + } + else + { + TicketIcon.SelectedMaterialIcon = MaterialIconType.ic_mail; + } + } + catch (Exception E) + { + LogException(E); + } + } + + private void CheckAffectedAssetIsCurrentAsset() + { + + try + { + WarningAssetHasBeenChanged.DataContext = this; + Binding visibilityBinding = new Binding(nameof(ShowAssetHasBeenChangedWarning)) + { + Converter = new BooleanToVisibilityConverter(), + }; + if (DataProvider == null) return; + + var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); + if (string.IsNullOrEmpty(computerName) || SelectedComputer == null) + { + AssetHasBeenChanged = false; + } + else + { + AssetHasBeenChanged = !SelectedComputer.DisplayName.Equals(computerName, StringComparison.OrdinalIgnoreCase); + } + WarningAssetHasBeenChanged.SetBinding(VisibilityProperty, visibilityBinding); + } + catch (Exception e) + { + LogException(e); + } + } + + private void CheckAffectedServiceIsCurrentService() + { + + try + { + WarningServiceHasBeenChanged.DataContext = this; + Binding visibilityBinding = new Binding(nameof(ShowServiceHasBeenChangedWarning)) + { + Converter = new BooleanToVisibilityConverter(), + }; + if (DataProvider == null) return; + + var service = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); + if (string.IsNullOrEmpty(service) || service == Guid.Empty.ToString() || SelectedService.Value == null) + { + ServiceHasBeenChanged = false; + } + else + { + ServiceHasBeenChanged = !SelectedService.Value.ToString().Equals(service, StringComparison.OrdinalIgnoreCase); + } + WarningServiceHasBeenChanged.SetBinding(VisibilityProperty, visibilityBinding); + } + catch (Exception e) + { + LogException(e); + } + } + + private void UpdateAffectedAssetComboBox() + { + try + { + if (DataProvider?.CaseRelations.TryGetValue(enumFasdInformationClass.Computer, out var computerRelationsTemp) != true) + return; + ComputerRelations = new List(computerRelationsTemp); + var currentlySelectedId = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer)?.Id; + var computerName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.Asset); + + + // Direktes Hinzufügen von Standardoptionen + var defaultOptions = new List(); + + // Hinzufügen basierend auf der Verfügbarkeit eines ausgewählten Elements + if (SelectedTicket != _newTicketRelation && !string.IsNullOrEmpty(computerName)) + { + var stringTemplate = cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedAssetEntry"); + _removeAffectedAssetEntry.DisplayName = string.Format(stringTemplate, computerName); + defaultOptions.AddRange(new[] { _removeAffectedAssetEntry }); + } + else + { + ComputerRelations.Remove(_removeAffectedAssetEntry); + } + var matchingRelation = ComputerRelations.FirstOrDefault(relation => relation.DisplayName == computerName); + + if (matchingRelation != null && !selectedTicketIsNewTicket) + { + ComputerRelations.Remove(matchingRelation); + } + ComputerRelations = ComputerRelations.Concat(defaultOptions).ToList(); + + var currentlySelectedComputer = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Computer); + if (currentlySelectedComputer != null) + SelectedComputer = ComputerRelations.FirstOrDefault(c => c.id == currentlySelectedComputer.Id); + else if (ComputerSelection.Items.Count > 0) + ComputerSelection.SelectedIndex = 0; + + if (currentlySelectedComputer == null || ComputerRelations.Any(x => RelationHasSpecialInfo(x, TicketSpecialValues.RemoveAffectedAssetEntry))) + SetOrUpdateComputerInTicket = false; + if (NewTicketPillSelected) + SetOrUpdateComputerInTicket = true; + + + } + catch (Exception e) + { + LogException(e); + } + } + + + private async void HandleServiceSearchDataChanged(object sender, cF4sdHealthSelectionDataRequest e) => await UpdateServiceSelectionControlAsync(e); + + private async Task UpdateServiceSelectionControlAsync(cF4sdHealthSelectionDataRequest requestData) + { + + try + { + string adDnUser = string.Empty; + + if (!cFasdCockpitCommunicationBase.Instance.IsDemo()) + { + if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-User", out var adDnUserParameter) && + !string.IsNullOrEmpty(adDnUserParameter.GetValue())) + { + adDnUser = adDnUserParameter.GetValue(); + } + else + { + return; + } + } + + requestData.Identities = DataProvider.Identities; + requestData.Table = "M42Wpm-Ticket-CloseCase-Services"; + requestData.FilterParams = new List { adDnUser }; + requestData.ResetFilter = ServiceSelectionControl.ResetFilter; + + if (string.IsNullOrEmpty(lastServiceSearch) || !lastServiceSearch.Equals(requestData.Search, StringComparison.OrdinalIgnoreCase)) + { + var resServiceCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); + ServiceSelectionControl.TotalItemCount = resServiceCount; + lastServiceSearch = requestData.Search; + } + + var serviceData = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); + var servicesList = GetServiceSelectionData(serviceData); + + var service = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceId); + var serviceName = GetSelectedTicketInfoOrDefault(TicketInfoKeys.ServiceName); + if (!string.IsNullOrEmpty(service) && Guid.Empty.ToString() != service) + { + + servicesList.Add(new KeyValuePair(string.Format(cMultiLanguageSupport.GetItem("Dialog.CloseCase.RemoveAffectedServiceEntry"), serviceName), TicketSpecialValues.RemoveAffectedServiceEntry)); + var itemToRemove = servicesList.FirstOrDefault(item => item.Value is string && (string)item.Value == service); + if (!itemToRemove.Equals(default(KeyValuePair))) + { + servicesList.Remove(itemToRemove); + } + } + else + { + var itemToRemove = servicesList.FirstOrDefault(x => string.Equals(x.Value.ToString(), TicketSpecialValues.RemoveAffectedServiceEntry, StringComparison.OrdinalIgnoreCase)); + if (itemToRemove.Key != null) + { + servicesList.Remove(itemToRemove); + } + } + ServiceSelectionControl.ItemData = servicesList; + } + catch (Exception E) + { + LogException(E); + } + } + + private ObservableCollection> GetServiceSelectionData(cF4SDHealthCardRawData.cHealthCardTable dataTable) + { + try + { + if (dataTable is null || dataTable.Name != "M42Wpm-Ticket-CloseCase-Services") + return null; + + if (!dataTable.Columns.TryGetValue("id", out var idColumn)) + return null; + + dataTable.Columns.TryGetValue("Name", out var nameColumn); + + var zippedKeyValuePairs = idColumn.Values.Zip(nameColumn.Values, (id, display) => new KeyValuePair(display.ToString(), id)); + + return new ObservableCollection>(zippedKeyValuePairs); + } + catch (Exception E) + { + LogException(E); + } + + return null; + } + + private async Task InitializeCategorySelectionAsync() + { + if (isCategoryLoading) + return; + + try + { + if (DataProvider == null || CategorySelectionControl == null) + return; + + isCategoryLoading = true; + + if (await TryPopulateCategoryHierarchyAsync(CategoryTableNamePrimary)) + { + CategorySelectionControl.ItemsSource = categoryHierarchy; + TrySelectTicketCategoryFromTicketInfos(); + } + } + catch (Exception E) + { + LogException(E); + } + finally + { + isCategoryLoading = false; + ValidateProperty(ValidationPropertyNames.SelectedCategory); + } + } + + private async Task TryPopulateCategoryHierarchyAsync(string tableName) + { + try + { + const int defaultPageSize = 250; + + var requestData = new cF4sdHealthSelectionDataRequest + { + Identities = DataProvider.Identities, + Table = tableName, + Page = 0, + PageSize = defaultPageSize, + Search = string.Empty + }; + + var totalCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); + var effectivePageSize = requestData.PageSize > 0 ? requestData.PageSize : defaultPageSize; + var pageCount = Math.Max(1, (int)Math.Ceiling((double)totalCount / Math.Max(1, effectivePageSize))); + + var flatItems = new Dictionary(StringComparer.OrdinalIgnoreCase); + + for (int pageIndex = 0; pageIndex < pageCount; pageIndex++) + { + requestData.Page = pageIndex; + requestData.PageSize = effectivePageSize; + + var categoryTable = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); + bool rowAdded = false; + + foreach (var item in ConvertCategoryTable(categoryTable)) + { + if (string.IsNullOrWhiteSpace(item.Id)) + continue; + + flatItems[item.Id] = item; + rowAdded = true; + } + + if (!rowAdded && categoryTable == null) + return false; + } + + var hierarchy = HierarchicalSelectionItem.BuildTree(flatItems.Values); + if (hierarchy == null || hierarchy.Count == 0) + return false; + + categoryHierarchy = hierarchy; + UpdateCategoryLookup(); + return true; + } + catch (Exception E) + { + LogException(E); + return false; + } + } + + private IEnumerable ConvertCategoryTable(cF4SDHealthCardRawData.cHealthCardTable dataTable) + { + if (dataTable == null || dataTable.Columns == null) + yield break; + + if (!dataTable.Columns.TryGetValue("id", out var idColumn)) + yield break; + + if (!dataTable.Columns.TryGetValue("Name", out var nameColumn)) + yield break; + + if (!dataTable.Columns.TryGetValue("parentValue", out cF4SDHealthCardRawData.cHealthCardTableColumn parentIdColumn)) + dataTable.Columns.TryGetValue("Parent_Value", out parentIdColumn); + if (!dataTable.Columns.TryGetValue("parent", out cF4SDHealthCardRawData.cHealthCardTableColumn parentNameColumn)) + dataTable.Columns.TryGetValue("Parent", out parentNameColumn); + + for (int index = 0; index < idColumn.Values.Count; index++) + { + var id = idColumn.Values[index]?.ToString(); + if (string.IsNullOrWhiteSpace(id)) + continue; + + var displayName = index < nameColumn.Values.Count ? nameColumn.Values[index]?.ToString() : string.Empty; + + string parentId = null; + if (parentIdColumn != null && index < parentIdColumn.Values.Count) + parentId = parentIdColumn.Values[index]?.ToString(); + + if (Guid.TryParse(parentId, out var parsedParentId) && parsedParentId == Guid.Empty) + parentId = null; + + var parentDisplayName = parentNameColumn != null && index < parentNameColumn.Values.Count + ? parentNameColumn.Values[index]?.ToString() + : null; + + yield return new HierarchicalSelectionItem + { + Id = id, + DisplayName = string.IsNullOrWhiteSpace(displayName) ? parentDisplayName ?? id : displayName, + ParentId = parentId, + ParentDisplayName = parentDisplayName + }; + } + } + + private void UpdateCategoryLookup() + { + categoryLookup.Clear(); + + if (categoryHierarchy == null) + return; + + foreach (var node in categoryHierarchy.SelectMany(item => item.SelfAndDescendants())) + { + if (!string.IsNullOrWhiteSpace(node.Id)) + categoryLookup[node.Id] = node; + } + } + + private void TrySelectTicketCategoryFromTicketInfos() + { + try + { + if (SelectedTicket?.Infos == null) + { + SelectedCategory = null; + return; + } + + if (!SelectedTicket.Infos.TryGetValue(TicketInfoKeys.Category, out var categoryId) || string.IsNullOrWhiteSpace(categoryId)) + { + SelectedCategory = null; + return; + } + + if (categoryLookup.TryGetValue(categoryId, out var categoryNode)) + SelectedCategory = categoryNode; + } + catch (Exception E) + { + LogException(E); + } + } + + private bool ShouldLoadCategoryFromDetails(cF4sdApiSearchResultRelation ticket) + { + if (ticket == null || ticket == _newTicketRelation || ticket == _selectTicketRelation || ticket == _noTicketRelation) + return false; + + if (ticket.Infos == null) + return true; + + if (!ticket.Infos.TryGetValue(TicketInfoKeys.Category, out var categoryValue) || string.IsNullOrWhiteSpace(categoryValue)) + return true; + + return !Guid.TryParse(categoryValue, out _); + } + + private async Task EnsureSelectedTicketCategoryFromDetailsAsync(cF4sdApiSearchResultRelation ticket) + { + try + { + if (!ShouldLoadCategoryFromDetails(ticket)) + return; + + var communication = cFasdCockpitCommunicationBase.Instance; + if (communication == null) + return; + + var request = new cF4sdHealthCardRawDataRequest + { + Tables = new List { TicketDetailsTableName }, + Identities = new cF4sdIdentityList + { + new cF4sdIdentityEntry { Class = enumFasdInformationClass.Ticket, Id = ticket.id } + }, + MaxAge = 1 + }; + + var rawData = await communication.GetHealthCardData(request).ConfigureAwait(false); + if (rawData?.Tables == null) + return; + + if (!rawData.Tables.TryGetValue(TicketDetailsTableName, out var ticketTable)) + return; + + if (!ticketTable.Columns.TryGetValue(TicketDetailsCategoryIdColumnName, out var categoryColumn)) + return; + + var categoryId = categoryColumn.Values?.FirstOrDefault()?.ToString(); + if (string.IsNullOrWhiteSpace(categoryId)) + return; + + await Dispatcher.InvokeAsync(() => + { + if (SelectedTicket == null) + return; + + if (!ReferenceEquals(SelectedTicket, ticket) && SelectedTicket.id != ticket.id) + return; + + if (SelectedTicket.Infos == null) + SelectedTicket.Infos = new Dictionary(StringComparer.OrdinalIgnoreCase); + + SelectedTicket.Infos[TicketInfoKeys.Category] = categoryId; + TrySelectTicketCategoryFromTicketInfos(); + }); + } + catch (Exception E) + { + LogException(E); + } + } + + private Guid? GetSelectedCategoryGuid() + { + if (SelectedCategory == null || string.IsNullOrWhiteSpace(SelectedCategory.Id)) + return null; + + if (Guid.TryParse(SelectedCategory.Id, out var categoryGuid)) + return categoryGuid; + + return null; + } + + private async Task UpdateQuickCallsComboBoxAsync() + { + try + { + cF4sdHealthSelectionDataRequest requestData = new cF4sdHealthSelectionDataRequest + { + Identities = DataProvider.Identities, + Table = "M42Wpm-Ticket-QuickCalls" + }; + + var resultCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData); + var quickCallsTable = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData); + + if (quickCallsTable == null) return; + + if (!quickCallsTable.Columns.TryGetValue("Name", out var namesColumn) || + !quickCallsTable.Columns.TryGetValue("id", out var idsColumn)) + { + return; + } + + quickCallsTable.Columns.TryGetValue("Category", out var categoryColumn); + + var quickCallListe = new List(); + + for (int i = 0; i < idsColumn.Values.Count; i++) + { + var id = idsColumn.Values[i].ToString(); + var name = namesColumn.Values[i].ToString(); + + Guid? categoryId = null; + if (categoryColumn?.Values != null && i < categoryColumn.Values.Count) + { + var categoryValue = categoryColumn.Values[i]?.ToString(); + if (Guid.TryParse(categoryValue, out var parsedCategory)) + categoryId = parsedCategory; + } + + quickCallListe.Add(new QuickCallEntry + { + ID = id, + DisplayName = name, + CategoryId = categoryId + }); + } + + QuickTicketSelection.ItemsSource = quickCallListe; + + QuickTicketSelection.SelectedItem = quickCallListe + .FirstOrDefault(x => x.ID == "7bbe64e2-94d0-ee11-4285-00155d010a04"); + ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + ApplyQuickCallCategorySelection(); + } + catch (Exception e) + { + LogException(e); + } + } + + public class QuickCallEntry + { + public string ID { get; set; } + public string DisplayName { get; set; } + public Guid? CategoryId { get; set; } + public override string ToString() + { + return DisplayName.ToString(); + } + } + + private void ApplyQuickCallCategorySelection() + { + try + { + if (!NewTicketPillSelected) + return; + + if (!(QuickTicketSelection?.SelectedItem is QuickCallEntry quickCall)) + return; + + if (!quickCall.CategoryId.HasValue || quickCall.CategoryId.Value == Guid.Empty) + return; + + var targetTicket = SelectedTicket ?? _selectTicketRelation; + if (targetTicket.Infos == null) + targetTicket.Infos = new Dictionary(StringComparer.OrdinalIgnoreCase); + + targetTicket.Infos[TicketInfoKeys.Category] = quickCall.CategoryId.Value.ToString(); + + if (ReferenceEquals(targetTicket, SelectedTicket)) + { + TrySelectTicketCategoryFromTicketInfos(); + } + else if (SelectedTicket == null && ReferenceEquals(targetTicket, _selectTicketRelation)) + { + SelectedTicket = targetTicket; + } + } + catch (Exception ex) + { + LogException(ex); + } + } + + + private void UpdateTicketSelection() + { + + try + { + TicketSelectionContainer.Children.Clear(); + + if (DataProvider is null) + return; + + if (!DataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var tempTicketRelations)) + return; + + var ticketRelations = new List(tempTicketRelations); + //ticketRelations.Insert(0, newTicketRelation); + //ticketRelations.Add(noTicketRelation); + + foreach (var ticketRelation in ticketRelations) + { + var tempTicketElement = GetTicketUiElement(ticketRelation); + + if (tempTicketElement is Border ticketBorder) + { + if (ticketRelations.FirstOrDefault() == ticketRelation) + ticketBorder.CornerRadius = new CornerRadius(7.5, 7.5, 0, 0); + else if (ticketRelations.LastOrDefault() == ticketRelation) + ticketBorder.CornerRadius = new CornerRadius(0, 0, 7.5, 7.5); + } + + if (tempTicketElement is null) + continue; + + TicketSelectionContainer.Children.Add(tempTicketElement); + } + + var currentlySelectedTicket = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket); + if (currentlySelectedTicket != null && !NewTicketPillSelected) + SelectedTicket = ticketRelations.FirstOrDefault(ticket => ticket.id == currentlySelectedTicket.Id); + } + catch (Exception E) + { + LogException(E); + } + } + + private void UpdateCaseNotesPreview() + { + try + { + if (DataProvider is null) + return; + + var caseNotesFlowDocument = DataProvider.CaseNotes; + StringBuilder caseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsUnicode(caseNotesFlowDocument.Blocks, caseNotes); + CaseNotesPreview.Text = caseNotes.ToString(); + } + catch (Exception E) + { + LogException(E); + } + + } + private void AddNewOrExistingOrNoneTicketSelection() + { + try + { + bool createTicket = _selectedTicket == null || SelectedTicket == _selectTicketRelation || selectedTicketIsNewTicket; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && + Enum.TryParse(statusIdString, true, out enumTicketStatus statusId)) + { + createTicket = statusId == enumTicketStatus.Closed; + SelectedTicket = SelectedTicket ?? _selectTicketRelation; + } + + TicketSelectionBorder.IsEnabled = !createTicket; + + var pillInfos = new (string, string, string, bool, bool)[] + { + ("Header.Create.Ticket", "CreateTicket", "misc_plus", false, createTicket), + ("Header.Select.Ticket", "SelectTicket", "ic_drafts", true, !createTicket), + ("Header.Skip.Ticket", "SkipTicket", "ic_block", true, false) + }; + NewTicketPillSelected = createTicket; + + foreach (var (textKey, tag, icon, isMaterialIcon, isSelected) in pillInfos) + { + var pillText = cMultiLanguageSupport.GetItem(textKey); + var selectionPill = new SelectionPill + { + PillText = pillText, + Tag = tag, + SelectOne = true, + GroupName = "NewUpdateNoTicketSelection", + IsSelected = isSelected + }; + + if (isMaterialIcon) + { + selectionPill.SelectedMaterialIcon = (MaterialIconType)Enum.Parse(typeof(MaterialIconType), icon); + } + else + { + selectionPill.SelectedInternIcon = (enumInternIcons)Enum.Parse(typeof(enumInternIcons), icon); + } + if (checkTicketActive()) + { + if (string.Equals(tag, "SelectTicket", StringComparison.OrdinalIgnoreCase)) + { + selectionPill.IsSelectedChanged += (s, e) => + { + TicketSelectionBorder.IsEnabled = selectionPill.IsSelected; + + + if (!DataProvider.CaseRelations.TryGetValue(enumFasdInformationClass.Ticket, out var tempTicketRelations)) + return; + + var ticketRelations = new List(tempTicketRelations); + var currentlySelectedTicket = DataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.Ticket); + SelectedTicket = SelectedTicket ?? ticketRelations.FirstOrDefault(ticket => ticket.id == currentlySelectedTicket.Id); + ValidateProperty(ValidationPropertyNames.SelectedTicket); + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + }; + } + else if (string.Equals(tag, "CreateTicket", StringComparison.OrdinalIgnoreCase)) + { + selectionPill.IsSelectedChanged += (s, e) => + { + NewTicketPillSelected = selectionPill.IsSelected; + SelectedTicket = selectionPill.IsSelected ? SelectedTicket : _selectTicketRelation; + if (selectionPill.IsSelected) + { + SelectedTicket = _selectTicketRelation; + ApplyQuickCallCategorySelection(); + } + ValidateProperty(ValidationPropertyNames.SelectedTicket); + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + }; + } + else if (string.Equals(tag, "SkipTicket", StringComparison.OrdinalIgnoreCase)) + { + selectionPill.IsSelectedChanged += (s, e) => + { + _skipTicketPillSelected = selectionPill.IsSelected; + _errors.Clear(); + UpdateTicketComponentVisibility(); + ValidateProperty(ValidationPropertyNames.SelectedTicket); + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + if (selectionPill.IsSelected) + { + TicketStatusCombobox.SelectedIndex = 0; + } + }; + } + NewOrExistingOrNoneTicketWrap.Children.Add(selectionPill); + } + } + } + catch (Exception E) + { + LogException(E); + } + } + private void AddCopyTemplates() + { + try + { + foreach (var copyTemplate in cF4SDCockpitXmlConfig.Instance.CopyTemplateConfig.CopyTemplates.CopyTemplates) + { + if (copyTemplate.Value.HiddenInTicketDialog) + continue; + + var selectionPill = new SelectionPill() { PillText = copyTemplate.Value.Names.GetValue(), Tag = copyTemplate.Value }; + + if (!string.IsNullOrWhiteSpace(copyTemplate.Value.Descriptions.GetValue())) + selectionPill.ToolTip = copyTemplate.Value.Descriptions.GetValue(); + + switch (copyTemplate.Value.Icon.IconType) + { + case enumIconType.intern: + if (Enum.TryParse(copyTemplate.Value.Icon.Name, out enumInternIcons internIcon)) + selectionPill.SelectedInternIcon = internIcon; + break; + case enumIconType.material: + if (Enum.TryParse(copyTemplate.Value.Icon.Name, out MaterialIcons.MaterialIconType materialIcon)) + selectionPill.SelectedMaterialIcon = materialIcon; + break; + case enumIconType.gif: + if (Enum.TryParse(copyTemplate.Value.Icon.Name, out enumInternGif internGif)) + selectionPill.SelectedGif = internGif; + break; + } + + CopyTemplateWrap.Children.Add(selectionPill); + } + } + catch (Exception E) + { + LogException(E); + } + } + + private string GetCopyText(enumCopyContentFormat format) + { + string output = string.Empty; + + try + { + if (CopyTemplateWrap.Children?.Count <= 0) + return string.Empty; + + foreach (var child in CopyTemplateWrap.Children) + { + if (!(child is SelectionPill selectionPill)) + continue; + + if (selectionPill.IsSelected == false) + continue; + + if (!(selectionPill.Tag is cCopyTemplate selectedCopyTemplate)) + continue; + + if (!selectedCopyTemplate.CopyContentList.TryGetValue(format, out cCopyContent copyContent)) + if (!selectedCopyTemplate.CopyContentList.TryGetValue(enumCopyContentFormat.UNICODE, out copyContent)) + continue; + + if (copyContent is null) + continue; + + if (!string.IsNullOrEmpty(output)) + output += format == enumCopyContentFormat.HTML ? "

" : "\n\n"; + + string copyText = copyContent.Content; + copyText = DataProvider.HealthCardDataHelper.ReplaceNamedParameters(copyText, format == enumCopyContentFormat.HTML); + + if (format == enumCopyContentFormat.HTML) + output += "
" + copyText + "
"; + else + output += copyText; + } + } + catch (Exception E) + { + LogException(E); + } + + return output; + } + + #region CloseCaseWithTicket + + private bool CloseCaseWithCopy() + { + try + { + StringBuilder asciiStringBuilder = new StringBuilder(); + StringBuilder htmlStringBuilder = new StringBuilder(); + + if (TransferCaseNotesCheck.IsChecked ?? false) + { + + var caseNotes = DataProvider.CaseNotes; + + var unicodeCaseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsUnicode(DataProvider.CaseNotes.Blocks, unicodeCaseNotes); + if (!string.IsNullOrWhiteSpace(unicodeCaseNotes.ToString())) + { + asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Summary") + ": \n"); + htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Summary") + ":
"); + asciiStringBuilder.Append(unicodeCaseNotes); + } + + var htmlCaseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsHtml(DataProvider.CaseNotes.Blocks, htmlCaseNotes); + if (!string.IsNullOrWhiteSpace(htmlCaseNotes.ToString())) + htmlStringBuilder.Append(htmlCaseNotes); + else + htmlStringBuilder.Append(unicodeCaseNotes); + } + + if (string.IsNullOrEmpty(asciiStringBuilder.ToString()) is false) + asciiStringBuilder.AppendLine(); + + if (string.IsNullOrEmpty(htmlStringBuilder.ToString()) is false) + htmlStringBuilder.AppendLine("

"); + + + var copyText = GetCopyText(enumCopyContentFormat.UNICODE); + if (!string.IsNullOrEmpty(copyText)) + { + asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.CopyTemplates") + ": \n"); + htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.CopyTemplates") + ":
"); + + asciiStringBuilder.AppendLine(copyText); + htmlStringBuilder.AppendLine(GetCopyText(enumCopyContentFormat.HTML)); + } + + if (TransferQuickActionHistoryCheck.IsChecked ?? false) + { + var quickActionProtocoll = F4SDProtocoll.Instance.GetAllAsDataObject(true); + var actionText = quickActionProtocoll.GetText(); + + if (!string.IsNullOrEmpty(actionText)) + { + + if (string.IsNullOrEmpty(asciiStringBuilder.ToString()) is false) + asciiStringBuilder.AppendLine(); + + if (string.IsNullOrEmpty(htmlStringBuilder.ToString()) is false) + htmlStringBuilder.AppendLine("

"); + + asciiStringBuilder.AppendLine(cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.QuickActions") + ": \n"); + htmlStringBuilder.AppendLine("" + cMultiLanguageSupport.GetItem("Dialog.CloseCase.Heading.QuickActions") + ":

"); + + asciiStringBuilder.AppendLine(quickActionProtocoll.GetText()); + htmlStringBuilder.AppendLine("
" + quickActionProtocoll.GetText(TextDataFormat.Html)); + } + } + + + DataObject tempDataObj = new DataObject(); + tempDataObj.SetText(asciiStringBuilder.ToString()); + tempDataObj.SetText(cUtility.GetHtmlFrame(htmlStringBuilder.ToString()), TextDataFormat.Html); + + System.Windows.Forms.Clipboard.SetDataObject(tempDataObj, true); + + return true; + } + catch (Exception E) + { + LogException(E); + } + + + return false; + } + + private async Task CloseCaseWithTicketAsync(Guid? userId = null) + { + var cm = MethodBase.GetCurrentMethod(); + LogMethodBegin(cm); + + try + { + if (SelectedTicket.Equals(_noTicketRelation)) + return false; + // Update Ticket Tables + const string ticketTable = "M42Wpm-Tickets"; + Dictionary ticketValues = new Dictionary() + { + ["UserId"] = userId, + + ["id"] = SelectedTicket.id, + [TicketInfoKeys.Summary] = TicketSummaryTextBox.Text, + ["CreationSource"] = 3, + ["Status"] = enumTicketStatus.Unknown, + ["time"] = DateTime.UtcNow, + ["Priority"] = 2, + }; + Guid quickcallId = Guid.Empty; + if (QuickTicketSelection.SelectedItem is QuickCallEntry selectedQuickTicketItem) + { + //ticketValues.Add("Category", selectedQuickTicketItem.DisplayName); + ticketValues.Add("QuickCallId", selectedQuickTicketItem.ID); + Guid.TryParse(selectedQuickTicketItem.ID?.ToString(), out quickcallId); + } + var selectedCategoryId = GetSelectedCategoryGuid(); + if (selectedCategoryId.HasValue) + ticketValues[TicketInfoKeys.Category] = selectedCategoryId.Value; + enumCloseCaseTicketStatus? closeCaseTicketStatus = null; + int errorType = -1; + var comment = string.Empty; + DateTime? reminderDate = null; + Guid? selectedRole = null; + Guid? selectedPerson = null; + if (TicketStatusCombobox.SelectedItem is ComboBoxItem selectedItem + && Enum.TryParse(selectedItem.Tag?.ToString(), out enumCloseCaseTicketStatus result)) + { + closeCaseTicketStatus = result; + switch (closeCaseTicketStatus) + { + case enumCloseCaseTicketStatus.Close: + ticketValues.Add("ClosingDate", DateTime.UtcNow); + ticketValues["Status"] = enumTicketStatus.Closed; + + if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicket) + { + ticketValues.Add("Solution", closeTicket.Solution); + if (closeTicket.ErrorTypeComboBox.SelectedItem is ComboBoxItem closeTicketComboBox) + { + int.TryParse(closeTicketComboBox.Tag?.ToString(), out errorType); + ticketValues.Add("ErrorType", closeTicketComboBox.Tag); + } + } + break; + case enumCloseCaseTicketStatus.OnHold: + { + if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicket) + { + comment = holdTicket.Comment; + } + } + ticketValues["Status"] = enumTicketStatus.OnHold; + break; + case enumCloseCaseTicketStatus.Forward: + if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicket) + { + var roleSelection = forwardTicket.RoleSelectionControl.GetSelectedValue(); + if (roleSelection.HasValue) + { + var roleSelectionval = roleSelection.Value.Value.ToString(); + if (Guid.TryParse(roleSelectionval, out var roleResult)) + { + selectedRole = roleResult; + } + } + var personSelection = forwardTicket.PersonSelectionControl.GetSelectedValue(); + if (personSelection.HasValue) + { + var personSelectionval = personSelection.Value.Value.ToString(); + if (Guid.TryParse(personSelectionval, out var personResult)) + { + selectedPerson = personResult; + } + } + comment = forwardTicket.Comment; + } + ticketValues["Status"] = enumTicketStatus.InProgress; + break; + default: + ticketValues["Status"] = enumTicketStatus.New; + break; + } + } + + string user = string.Empty; + if (DataProvider.NamedParameterEntries.TryGetValue("UserFullName", out var userNameParameter)) + user = userNameParameter.GetValue(); + ticketValues.Add("AffectedUser", user); + string asset = string.Empty; + if (SelectedComputer == _removeAffectedAssetEntry) + { + asset = TicketSpecialValues.RemoveAffectedAssetEntry; + } + else if (SetOrUpdateComputerInTicket) + { + asset = SelectedComputer?.DisplayName; + } + + ticketValues.Add("Asset", asset); + + Guid? service = null; + if (SetOrUpdateServiceInTicket && SelectedService.Value != null) + { + if (string.Equals(SelectedService.Value.ToString(), TicketSpecialValues.RemoveAffectedServiceEntry, StringComparison.OrdinalIgnoreCase)) + service = Guid.Empty; + else if (Guid.TryParse(SelectedService.Value.ToString(), out Guid parsedGuid)) + { + service = parsedGuid; + } + } + + + string adDnComputer = string.Empty; + string userFullName = string.Empty; + string userAccount = string.Empty; + string adDnUser = string.Empty; + string userMail = string.Empty; + + // Abrufen der Variablenwerte aus den NamedParameterEntries + if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-computer", out var adDnComputerParameter)) + { + adDnComputer = adDnComputerParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("UserFullName", out var userFullNameParameter)) + { + userFullName = userFullNameParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("UserAccount", out var userAccountParameter)) + { + userAccount = userAccountParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("ad-dn-User", out var adDnUserParameter)) + { + adDnUser = adDnUserParameter.GetValue(); + } + + if (DataProvider.NamedParameterEntries.TryGetValue("UserMail", out var userMailParameter)) + { + userMail = userMailParameter.GetValue(); + } + + var htmlCaseNotes = new StringBuilder(); + if (TransferCaseNotesCheck.IsChecked ?? false) + { + var caseNotes = DataProvider.CaseNotes; + + var unicodeCaseNotes = new StringBuilder(); + cRichTextBoxHelper.TraverseBlockAsUnicode(DataProvider.CaseNotes.Blocks, unicodeCaseNotes); + if (!string.IsNullOrWhiteSpace(unicodeCaseNotes.ToString())) + ticketValues.Add("Description", unicodeCaseNotes.ToString()); + + cRichTextBoxHelper.TraverseBlockAsHtml(DataProvider.CaseNotes.Blocks, htmlCaseNotes); + if (!string.IsNullOrWhiteSpace(htmlCaseNotes.ToString())) + ticketValues.Add("DescriptionHtml", htmlCaseNotes.ToString()); + } + + const string journalTable = "M42Wpm-Tickets-History"; + + //Update QuickAction History + string solutionHtmlString = string.Empty; + Dictionary quickActionValues = null; + + if (ticketValues.TryGetValue("Solution", out var solutionValue)) + { + if (solutionValue is string solutionString) + { + if (!string.IsNullOrWhiteSpace(solutionString)) + { + solutionString += "\n\n\n"; + solutionHtmlString = solutionString + "


"; + } + else + { + solutionHtmlString = "


"; + } + + ticketValues["Solution"] = solutionString; + ticketValues["SolutionHtml"] = solutionHtmlString; + } + } + + if (TransferQuickActionHistoryCheck.IsChecked ?? false) + { + var quickActionProtocoll = F4SDProtocoll.Instance.GetAllAsDataObject(true); + + if (ticketValues.TryGetValue("Solution", out solutionValue)) + { + if (solutionValue is string solutionString) + { + solutionString += quickActionProtocoll.GetText(); + solutionHtmlString += quickActionProtocoll.GetText(TextDataFormat.Html); + + ticketValues["Solution"] = solutionString; + ticketValues["SolutionHtml"] = solutionHtmlString; + } + } + else + { + var tempQuickActionValues = new Dictionary() + { + ["UserId"] = userId, + ["id"] = SelectedTicket.id, + ["Header"] = "Commented by F4SD", + ["IsVisibleForUser"] = false, + ["time"] = DateTime.UtcNow, + ["Description"] = quickActionProtocoll.GetText(), + ["DescriptionHtml"] = string.IsNullOrWhiteSpace(quickActionProtocoll.GetText(TextDataFormat.Html)) + ? quickActionProtocoll.GetText() + : quickActionProtocoll.GetText(TextDataFormat.Html) + }; + + if (!string.IsNullOrWhiteSpace(quickActionProtocoll.GetText())) + quickActionValues = tempQuickActionValues; + } + } + + await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = ticketTable, Values = ticketValues }); + + if (quickActionValues != null) + await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = journalTable, Values = quickActionValues }); + + string copyString = GetCopyText(enumCopyContentFormat.UNICODE); + string copyStringHtml = GetCopyText(enumCopyContentFormat.HTML); + if (!string.IsNullOrWhiteSpace(copyString)) + { + Dictionary copyValues = new Dictionary() + { + ["UserId"] = userId, + + ["id"] = SelectedTicket.id, + ["Header"] = "Commented by F4SD", + ["IsVisibleForUser"] = false, + ["time"] = DateTime.UtcNow, + ["Description"] = copyString, + ["DescriptionHtml"] = string.IsNullOrWhiteSpace(copyStringHtml) ? copyString : copyStringHtml + }; + await cFasdCockpitCommunicationBase.Instance.UpdateHealthcardTableData(new cF4SDWriteParameters() { id = SelectedTicket.id, TableName = journalTable, Values = copyValues }); + } + + string statusIdValue = null; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var value)) + { + statusIdValue = value; + } + + + var workingTimes = TimerView.GetWorkTimes(); + workingTimes.Add("Description", cMultiLanguageSupport.GetItem("Dialog.CloseCase.WorkingTimeEntryDescription")); + var doNotEscalate = false; + var holdTicketReason = 0; + if (this.DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog) + { + reminderDate = new DateTime( + holdTicketDialog.SelectedDate.Year, + holdTicketDialog.SelectedDate.Month, + holdTicketDialog.SelectedDate.Day, + holdTicketDialog.SelectedHour, + holdTicketDialog.SelectedMinute, + 0); + doNotEscalate = (bool)holdTicketDialog.DoNotEscalate.IsChecked; + if (holdTicketDialog.ReasonSelection.SelectedItem is ComboBoxItem sel) + { + if (int.TryParse(sel.Tag.ToString(), out int tmpReasonTag)) + { + holdTicketReason = tmpReasonTag; + } + } + } + cApiM42Ticket ticketData = new cApiM42Ticket() + { + Ticket = _selectedTicket.Identities == null ? Guid.Empty : SelectedTicket.id, + Action = closeCaseTicketStatus.HasValue ? closeCaseTicketStatus : null, + User = adDnUser, + AffectedAsset = asset, + AffectedService = service, + Category = selectedCategoryId, + Summary = TicketSummaryTextBox.Text, + DescriptionHtml = htmlCaseNotes.ToString(), + Quickcall = quickcallId, + CopyTemplates = string.IsNullOrWhiteSpace(copyStringHtml) ? copyString : copyStringHtml, + SolutionHtml = solutionHtmlString, + ErrorType = errorType, + ReminderDate = reminderDate, + DoNotEscalateWhilePaused = doNotEscalate, + Reason = holdTicketReason, + ResponsibleRole = selectedRole, + ResponsiblePerson = selectedPerson, + Comment = comment, + SupportCaseProtocollEntries = TransferQuickActionHistoryCheck.IsChecked ?? false ? F4SDProtocoll.Instance.GetAll().ToList() : null, + workTimes = workingTimes, + StatusIdValue = statusIdValue, + CaseId = DataProvider.CaseId + }; + ticketData.AdditionalValues.Add("IsTicket", IsTicket); + ticketData.AdditionalValues.Add(TicketInfoKeys.ActivityType, GetSelectedTicketInfoOrDefault(TicketInfoKeys.ActivityType)); + ticketData.AdditionalValues.Add("Dialog.CloseCase.AssetNotFoundInMatrix42", cMultiLanguageSupport.GetItem("Dialog.CloseCase.AssetNotFoundInMatrix42")); + ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonText", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonText")); + ticketData.AdditionalValues.Add("Dialog.CloseCase.ReopenReasonTextHtml", cMultiLanguageSupport.GetItem("Dialog.CloseCase.ReopenReasonTextHtml")); + var _res = await cFasdCockpitCommunicationBase.Instance.Matrix42TicketFinalization(ticketData); + return true; + } + catch (Exception e) + { + LogException(e); + } + finally + { + LogMethodEnd(cm); + } + return false; + } + + public async Task CloseCaseAsync(Guid? userId = null) + { + try + { + + if (checkTicketActive() && !_skipTicketPillSelected) + return await CloseCaseWithTicketAsync(userId); + else + return CloseCaseWithCopy(); + } + catch (Exception E) + { + LogException(E); + } + + return false; + } + + #endregion + + + public List GetErrors(string propertyName) + { + switch (propertyName) + { + case ValidationPropertyNames.SelectedTicket: + if (SelectedTicket == _selectTicketRelation && !NewTicketPillSelected && !SkipTicketPillSelected) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Header.Select.Ticket")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + break; + case ValidationPropertyNames.TicketSummaryTextBox: + validateTextboxNotEmpty(TicketSummaryTextBox); + if (!string.IsNullOrEmpty(TicketSummaryTextBox.Text) || !TicketSummaryTextBox.IsVisible) + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + else + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorSummaryEmpty")); + } + break; + case ValidationPropertyNames.CaseNotesPreview: + var errorNotEmpty = CheckTextBlockNotEmpty(CaseNotesPreview, cFasdCockpitConfig.Instance.Global.TicketConfiguration.NotesMandatory); + if (errorNotEmpty && CaseNotesPreview.IsVisible) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorCaseNoteEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + break; + case ValidationPropertyNames.SolutionTextbox: + if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicketDialog) + { + if (string.IsNullOrEmpty(closeTicketDialog.Solution)) + { + setTextboxErrorState(closeTicketDialog.SolutionTextbox, true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorSolutionEmpty")); + } + else + { + setTextboxErrorState(closeTicketDialog.SolutionTextbox, false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + case ValidationPropertyNames.ReminderDate: + if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog) + { + if (holdTicketDialog.SelectedReminderDate <= DateTime.UtcNow.AddMinutes(-2)) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorReminderDate")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.ErrorTypeValue: + if (DynamicStatusAdditionBorder.Child is CloseTicketDialog closeTicketDialog2) + { + if (closeTicketDialog2.SelectedErrorType == null || closeTicketDialog2.SelectedErrorType is ComboBoxItem b && b.Tag == null) + { + closeTicketDialog2.UpdateErrorTypeValidationState(true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorTypeEmpty")); + } + else + { + closeTicketDialog2.UpdateErrorTypeValidationState(false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.SelectedRoleAndPerson: + if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicketDialog) + { + bool hasError = (forwardTicketDialog.SelectedPerson.Key == null || forwardTicketDialog.SelectedPerson.Value == null) && + (forwardTicketDialog.SelectedRole.Key == null || forwardTicketDialog.SelectedRole.Value == null); + + forwardTicketDialog.UpdateResponsibleSelectionValidationState(hasError); + + if (hasError) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorRoleAndPersonEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.ForwardComment: + if (DynamicStatusAdditionBorder.Child is ForwardTicketDialog forwardTicketDialog2) + { + if (string.IsNullOrEmpty(forwardTicketDialog2.Comment)) + { + setTextboxErrorState(forwardTicketDialog2.CommentTextbox, true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ForwardTicket.ValidationErrorCommentEmpty")); + } + else + { + setTextboxErrorState(forwardTicketDialog2.CommentTextbox, false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + case ValidationPropertyNames.HoldComment: + if (DynamicStatusAdditionBorder.Child is HoldTicketDialog holdTicketDialog1) + { + if (string.IsNullOrEmpty(holdTicketDialog1.Comment)) + { + setTextboxErrorState(holdTicketDialog1.CommentTextBox, true); + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.HoldTicket.ValidationErrorCommentEmpty")); + } + else + { + setTextboxErrorState(holdTicketDialog1.CommentTextBox, false); + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + } + break; + + case ValidationPropertyNames.TicketStatusCombobox: + if (!(TicketStatusCombobox.SelectedItem is ComboBoxItem a)) + break; + + enumTicketStatus currentTicketStatus = enumTicketStatus.Unknown; + if (TryGetSelectedTicketInfo(TicketInfoKeys.StatusId, out var statusIdString) && + Enum.TryParse(statusIdString, true, out enumTicketStatus parsedStatus)) + { + currentTicketStatus = parsedStatus; + } + + bool ticketActionHasError = TicketStatusCombobox.IsVisible && a.Tag == null; + if (!ticketActionHasError) + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + else if (!_errors.ContainsKey(propertyName)) + { + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorTicketActionEmpty")); + } + UpdateTicketStatusValidationVisualState(ticketActionHasError); + + if (a.Tag == null) + { + ShowAssetWarningTicketAction = false; + break; + } + + enumCloseCaseTicketStatus? selectedStatus = null; + if (Enum.TryParse(a.Tag.ToString(), true, out enumCloseCaseTicketStatus parsedStatusAction)) + { + selectedStatus = parsedStatusAction; + } + + bool hasTicketActivity = TryGetSelectedTicketInfo(TicketInfoKeys.ActivityType, out var currentTicketActivityType) && + string.Equals(currentTicketActivityType, TicketInfoValues.ActivityTypeTicket, StringComparison.OrdinalIgnoreCase); + + if (selectedStatus.HasValue && selectedStatus != enumCloseCaseTicketStatus.Forward && selectedStatus != enumCloseCaseTicketStatus.Save && hasTicketActivity) + { + ShowAssetWarningTicketAction = true; + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = "Dialog.CloseCase.ValidationErrorTicketToIncident" + }; + + WarningTicketAction.SetBinding(ToolTipProperty, binding); + } + else if (currentTicketStatus == enumTicketStatus.Closed) + { + ShowAssetWarningTicketAction = true; + var binding = new Binding + { + Converter = _languageConverter, + ConverterParameter = "Dialog.CloseCase.ValidationErrorTicketWillBeReopened" + }; + + WarningTicketAction.SetBinding(ToolTipProperty, binding); + } + else + { + ShowAssetWarningTicketAction = false; + } + + break; + case ValidationPropertyNames.SelectedCategory: + bool categoryIsVisible = CategorySelectionControl?.IsVisible ?? false; + bool categoryHasError = categoryIsVisible && SelectedCategory == null; + UpdateCategoryValidationVisualState(categoryHasError); + + if (categoryHasError) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorCategoryEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + + break; + case ValidationPropertyNames.QuickTicketSelection: + bool quickCallIsVisible = QuickTicketSelection?.IsVisible ?? false; + bool quickCallSelected = QuickTicketSelection?.SelectedItem is QuickCallEntry selectedQuickCall && !string.IsNullOrWhiteSpace(selectedQuickCall.ID); + bool quickCallHasError = quickCallIsVisible && !quickCallSelected; + UpdateQuickTicketValidationVisualState(quickCallHasError); + + if (quickCallHasError) + { + if (!_errors.ContainsKey(propertyName)) + _errors.Add(propertyName, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorQuickCallEmpty")); + } + else + { + if (_errors.ContainsKey(propertyName)) + _errors.Remove(propertyName); + } + + break; + } + + return new List(_errors.Values); + } + + + private void ValidateProperty(string propertyName) + { + var errors = GetErrors(propertyName); + if (errors != null && errors.Count > 0) + { + // Speichern-Button deaktivieren + if (Window.GetWindow(this) is TicketCompletion msgBox) + { + this.parentWindow = msgBox; + this.parentWindow.SetButtonStateYes(false, cMultiLanguageSupport.GetItem("Dialog.CloseCase.ValidationErrorsList") + "\r\n• " + string.Join("\r\n• ", errors)); + } + } + else + { + // Speichern-Button aktivieren + Window parentWindow = Window.GetWindow(this); + + if (parentWindow is TicketCompletion _msgBox) + { + this.parentWindow = _msgBox; + this.parentWindow.SetButtonStateYes(true, ""); + } + } + } + + #region TicketRelation_Click + + private void TicketRelation_Click(object sender) + { + try + { + if (!(sender is FrameworkElement senderElement)) + return; + + if (!(senderElement.Tag is cF4sdApiSearchResultRelation selectedSearchResult)) + return; + + SelectedTicket = selectedSearchResult; + UpdateSelectedTicketControl(); + TicketSelectionPopUp.IsOpen = false; + } + catch (Exception E) + { + LogException(E); + } + } + + private void TicketRelation_TouchDown(object sender, TouchEventArgs e) + { + TicketRelation_Click(sender); + } + + private void TicketRelation_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + TicketRelation_Click(sender); + } + + #endregion + + #region EditCaseNotesButton_Click + + private void EditCaseNotesButton_Click() + { + try + { + if (SupportNotepad == false) + { + return; + } + + + TicketNotepadChanged?.Invoke(this, true); + + //TODO + //var notepad = new Notepad(true, DataProvider.caseNotes) { DataProvider = DataProvider }; + //openedWindows.Add(Window.GetWindow(notepad)); + } + catch (Exception E) + { + LogException(E); + } + + } + + private void EditCaseNotesButton_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + EditCaseNotesButton_Click(); + + if (!string.IsNullOrWhiteSpace(CaseNotesPreview.Text)) + { + CaseNotesPreviewBorder.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); + ValidateProperty(ValidationPropertyNames.CaseNotesPreview); + } + else + { + CaseNotesPreviewBorder.BorderBrush = SharedValidationBorderBrush; + } + } + + private void EditCaseNotesButton_TouchDown(object sender, TouchEventArgs e) + { + EditCaseNotesButton_Click(); + } + + #endregion + + private void TicketStatusCombobox_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + + if (DynamicStatusAdditionBorder is null) + return; + + if (!(sender is ComboBox comboBox)) + return; + + // Die Werte aus 'errors' entfernen + Array.ForEach( + new[] + { + ValidationPropertyNames.SolutionTextbox, + ValidationPropertyNames.ErrorTypeValue, + ValidationPropertyNames.ReminderDate, + ValidationPropertyNames.SelectedRoleAndPerson, + ValidationPropertyNames.ForwardComment, + ValidationPropertyNames.HoldComment + }, + key => _errors.Remove(key)); + ValidateProperty(ValidationPropertyNames.TicketStatusCombobox); + + if (!(comboBox.SelectedItem is ComboBoxItem selectedItem)) + return; + if (!(Enum.TryParse(selectedItem.Tag?.ToString(), out enumCloseCaseTicketStatus closeCaseTicketStatus))) + { + DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed; + return; + } + + FrameworkElement dynamicStatusChild = null; + switch (closeCaseTicketStatus) + { + case enumCloseCaseTicketStatus.Close: + var dialog = new CloseTicketDialog() { DataProvider = DataProvider }; + dialog.ErrorTypeValueChanged += Dialog_ErrorTypeValueChanged; + dialog.SolutionValueChanged += SolutionTextboxValueChanged; + var _h = Dispatcher.BeginInvoke((Action)(() => + { + if (dialog.IsLoaded) + { + ValidateProperty(ValidationPropertyNames.SolutionTextbox); + ValidateProperty(ValidationPropertyNames.ErrorTypeValue); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + + + dynamicStatusChild = dialog; + break; + case enumCloseCaseTicketStatus.OnHold: + var holdTicketDialog = new HoldTicketDialog(DataProvider = DataProvider); + dynamicStatusChild = holdTicketDialog; + holdTicketDialog.SelectedReminderDateChanged += ReminderDateValueChanged; + holdTicketDialog.CommentChanged += HoldCommentChanged; + _h = Dispatcher.BeginInvoke((Action)(() => + { + if (holdTicketDialog.IsLoaded) + { + ValidateProperty(ValidationPropertyNames.ReminderDate); + ValidateProperty(ValidationPropertyNames.HoldComment); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + break; + case enumCloseCaseTicketStatus.Forward: + var forwardTicketDialog = new ForwardTicketDialog(DataProvider); + dynamicStatusChild = forwardTicketDialog; + forwardTicketDialog.SelectedPersonChanged += SelectedPersonChanged; + forwardTicketDialog.SelectedRoleChanged += SelectedRoleChanged; + forwardTicketDialog.CommentChanged += ForwardCommentChanged; + _h = Dispatcher.BeginInvoke((Action)(() => + { + if (forwardTicketDialog.IsLoaded) + { + ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); + ValidateProperty(ValidationPropertyNames.ForwardComment); + } + }), System.Windows.Threading.DispatcherPriority.Loaded); + break; + case enumCloseCaseTicketStatus.Save: + break; + } + if (dynamicStatusChild != null) + { + DynamicStatusAdditionBorder.Visibility = Visibility.Visible; + DynamicStatusAdditionBorder.Child = dynamicStatusChild; + } + else + DynamicStatusAdditionBorder.Visibility = Visibility.Collapsed; + this.VerticalAlignment = VerticalAlignment.Center; + } + private void ForwardCommentChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.ForwardComment); + } + private void HoldCommentChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.HoldComment); + } + private void SelectedRoleChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); + } + + private void SelectedPersonChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.SelectedRoleAndPerson); + } + + private void ReminderDateValueChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.ReminderDate); + } + private void SolutionTextboxValueChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.SolutionTextbox); + } + + private void Dialog_ErrorTypeValueChanged(object sender, EventArgs e) + { + ValidateProperty(ValidationPropertyNames.ErrorTypeValue); + } + + private void TicketSelectionBorder_Click() + { + var _h = Dispatcher.Invoke(async () => + { + await Task.Delay(50); + + if (!TicketSelectionPopUp.IsOpen) + DropDownOpened(TicketSelectionBorder, EventArgs.Empty); + + TicketSelectionPopUp.IsOpen = !TicketSelectionPopUp.IsOpen; + }); + } + + private void TicketSelectionBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) + { + TicketSelectionBorder_Click(); + } + + private void TicketSelectionBorder_TouchDown(object sender, TouchEventArgs e) + { + TicketSelectionBorder_Click(); + } + + private void TicketSummaryTextBox_TextChanged(object sender, TextChangedEventArgs e) + { + try + { + if (SelectedTicket?.Infos is null) + return; + + SelectedTicket.Infos[TicketInfoKeys.Summary] = TicketSummaryTextBox.Text; + ValidateProperty(ValidationPropertyNames.TicketSummaryTextBox); + } + catch (Exception E) + { + LogException(E); + } + + } + + private void TicketCaseNotesTextBlock_TextChanged(object sender, EventArgs e) + { + try + { + if (SelectedTicket?.Infos is null) + return; + + if (string.IsNullOrWhiteSpace(CaseNotesPreview.Text)) + CaseNotesPreview.Text = string.Empty; + + ValidateProperty(ValidationPropertyNames.CaseNotesPreview); + } + catch (Exception E) + { + LogException(E); + } + } + + private static void validateTextboxNotEmpty(object sender) + { + if (sender is TextBox textBox) + { + // Text aus der TextBox holen + string text = textBox.Text; + + // Überprüfe den Inhalt und setze die Hintergrundfarbe entsprechend + if (string.IsNullOrWhiteSpace(text)) + { + // Setze die Hintergrundfarbe auf Rot, um einen Validierungsfehler anzuzeigen + textBox.BorderBrush = SharedValidationBorderBrush; + } + else + { + // Setze die ursprüngliche Hintergrundfarbe zurück, wenn die Validierung erfolgreich ist + textBox.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); + } + } + } + + + private bool CheckTextBlockNotEmpty(TextBlock _textBlock, bool notEmpty) + { + var _retVal = false; + Brush _borderCaseNores = DefaultTextBoxBorderBrush; + if (notEmpty && string.IsNullOrWhiteSpace(_textBlock.Text)) + { + _retVal = true; + _borderCaseNores = SharedValidationBorderBrush; + } + CaseNotesPreviewBorder.BorderBrush = _borderCaseNores; + return _retVal; + } + + + private static void setTextboxErrorState(object sender, bool hasError) + { + if (!(sender is TextBox textBox)) + return; + + textBox.BorderBrush = hasError ? SharedValidationBorderBrush : DefaultTextBoxBorderBrush; + } + + private void UpdateCategoryValidationVisualState(bool hasError) => + UpdateValidationBorderState(CategoryValidationBorder, ref defaultCategoryBorderBrush, ref defaultCategoryBorderThickness, hasError); + + private void UpdateQuickTicketValidationVisualState(bool hasError) => + UpdateValidationBorderState(QuickTicketValidationBorder, ref defaultQuickTicketBorderBrush, ref defaultQuickTicketBorderThickness, hasError); + + private void UpdateTicketStatusValidationVisualState(bool hasError) => + UpdateValidationBorderState(TicketStatusValidationBorder, ref defaultTicketStatusBorderBrush, ref defaultTicketStatusBorderThickness, hasError); + + private void UpdateValidationBorderState(Border border, ref Brush defaultBrush, ref Thickness? defaultThickness, bool hasError) + { + if (border == null) + return; + + if (defaultBrush == null) + { + var borderBrush = border.BorderBrush; + defaultBrush = borderBrush?.CloneCurrentValue(); + } + + if (!defaultThickness.HasValue) + defaultThickness = border.BorderThickness; + + border.BorderBrush = hasError ? validationErrorBrush : defaultBrush; + border.BorderThickness = hasError ? new Thickness(1) : defaultThickness ?? new Thickness(0); + } + + + + #region DropDown + private static bool IsInsidePageable(FrameworkElement fe) => cUiElementHelper.GetFirstParentOfType(fe) != null; + + public bool TryHandleEscapeKey() + { + try + { + if (TicketSelectionPopUp?.IsOpen == true) + { + TicketSelectionPopUp.IsOpen = false; + return true; + } + + if (QuickTicketSelection?.IsDropDownOpen == true) + { + QuickTicketSelection.IsDropDownOpen = false; + return true; + } + + if (CategorySelectionControl?.CloseDropDownIfOpen() == true) + return true; + + if (ComputerSelection?.IsDropDownOpen == true) + { + ComputerSelection.IsDropDownOpen = false; + return true; + } + + if (ServiceSelectionControl?.CloseDropDownIfOpen() == true) + return true; + + if (TicketStatusCombobox?.IsDropDownOpen == true) + { + TicketStatusCombobox.IsDropDownOpen = false; + return true; + } + } + catch (Exception E) + { + LogException(E); + } + + return false; + } + + private void DropDownOpened(object sender, EventArgs e) + { + if (!(sender is FrameworkElement fe)) return; + if (IsInsidePageable(fe)) return; // ComboBoxPageable fired itself + + var parentBorder = cUiElementHelper.GetFirstParentOfType(fe); + if (parentBorder != null) + cFocusInvoker.InvokeGotFocus(parentBorder, e); + } + + private void RestoreDialogFocusAfterTicketActionSelection() + { + try + { + if (DialogContentScrollViewer == null) + return; + + Keyboard.ClearFocus(); + DialogContentScrollViewer.Focus(); + Keyboard.Focus(DialogContentScrollViewer); + } + catch (Exception E) + { + LogException(E); + } + } + + public void SetDialogContentMaxHeight(double maxHeight) + { + try + { + if (DialogContentScrollViewer == null) + return; + + // Keep dialog usable on very small screens; parent window already constrains max size. + DialogContentScrollViewer.MaxHeight = Math.Max(MinDialogContentHeightDip, maxHeight); + } + catch (Exception E) + { + LogException(E); + } + } + + private void DropDownClosed(object sender, EventArgs e) + { + if (!(sender is FrameworkElement fe)) return; + if (IsInsidePageable(fe)) return; + + var parentBorder = cUiElementHelper.GetFirstParentOfType(fe); + if (parentBorder != null) + cFocusInvoker.InvokeLostFocus(parentBorder, e); + + _ = Dispatcher.BeginInvoke(new Action(RestoreDialogFocusAfterTicketActionSelection), System.Windows.Threading.DispatcherPriority.Input); + } + + #endregion + + private void TicketSelectionPopUp_Closed(object sender, EventArgs e) + { + DropDownClosed(TicketSelectionBorder, e); + } + + private void TransferCaseNotesCheck_Checked(object sender, RoutedEventArgs e) + { + try + { + CaseNotesPreview?.ClearValue(OpacityProperty); + CaseNotesPreviewBorder?.ClearValue(IsHitTestVisibleProperty); + } + catch (Exception E) + { + LogException(E); + } + + } + private void ComputerSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + SelectedComputer = (cF4sdApiSearchResultRelation)ComputerSelection.SelectedItem; + } + + private void QuickTicketSelection_SelectionChanged(object sender, SelectionChangedEventArgs e) + { + ValidateProperty(ValidationPropertyNames.QuickTicketSelection); + ApplyQuickCallCategorySelection(); + } + + private void TransferCaseNotesCheck_Unchecked(object sender, RoutedEventArgs e) + { + try + { + if (CaseNotesPreview != null) + CaseNotesPreview.Opacity = 0.7; + + if (CaseNotesPreviewBorder != null) + CaseNotesPreviewBorder.IsHitTestVisible = false; + } + catch (Exception E) + { + LogException(E); + } + + } + + private void CloseCaseDialogUc_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e) + { + try + { + if (!(e.NewValue is bool isVisible && !isVisible)) + return; + + foreach (Window window in _openedWindows) + { + if (window is null) + continue; + + window.Close(); + } + } + catch (Exception E) + { + LogException(E); + } + + } + + private void Combobox_PreviewKeyDown(object sender, KeyEventArgs e) + { + if (e.Key == Key.Escape) + { + if (sender is FrameworkElement fe && IsInsidePageable(fe)) return; + DropDownClosed(sender, e); + } + } + } +} diff --git a/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml.cs b/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml.cs index e482296..296ed42 100644 --- a/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml.cs +++ b/FasdDesktopUi/Pages/TicketCompletion/TicketCompletion.xaml.cs @@ -3,26 +3,26 @@ using FasdDesktopUi.Basics; using FasdDesktopUi.Basics.Models; using System; using System.ComponentModel; -using System.Linq; -using System.Reflection; -using System.Threading.Tasks; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Interop; -using System.Windows.Media; -using WinForms = System.Windows.Forms; -using static C4IT.Logging.cLogManager; +using System.Linq; +using System.Reflection; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Interop; +using System.Windows.Media; +using WinForms = System.Windows.Forms; +using static C4IT.Logging.cLogManager; namespace FasdDesktopUi.Pages.TicketCompletion { - public partial class TicketCompletion : Window, IBlurInvoker, INotifyPropertyChanged - { - private const double MinWindowHeightDip = 220d; - private const double WindowWorkingAreaMarginDip = 12d; - private const double DialogNonContentReserveDip = 180d; - private bool isUpdatingDialogBounds; - private bool isCanceled = false; + public partial class TicketCompletion : Window, IBlurInvoker, INotifyPropertyChanged + { + private const double MinWindowHeightDip = 220d; + private const double WindowWorkingAreaMarginDip = 12d; + private const double DialogNonContentReserveDip = 180d; + private bool isUpdatingDialogBounds; + private bool isCanceled = false; private bool _WaitForClosing = false; public bool WaitForClosing @@ -49,31 +49,31 @@ namespace FasdDesktopUi.Pages.TicketCompletion CloseCaseDialogUc.DataProvider = _dataProvider; } - protected override void OnInitialized(EventArgs e) - { - base.OnInitialized(e); - - cFocusInvoker.GotFocus += ElementGotFocus; - cFocusInvoker.LostFocus += ElementLostFocus; - SizeChanged += TicketCompletion_SizeChanged; - Loaded += TicketCompletion_Loaded; - } - - protected override void OnSourceInitialized(EventArgs e) - { - base.OnSourceInitialized(e); - UpdateDialogMaxHeightToScreen(); - } - - protected override void OnLocationChanged(EventArgs e) - { - base.OnLocationChanged(e); - UpdateDialogMaxHeightToScreen(); - } - - private void TicketCompletion_Loaded(object sender, RoutedEventArgs e) => UpdateDialogMaxHeightToScreen(); - - private void TicketCompletion_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateDialogMaxHeightToScreen(); + protected override void OnInitialized(EventArgs e) + { + base.OnInitialized(e); + + cFocusInvoker.GotFocus += ElementGotFocus; + cFocusInvoker.LostFocus += ElementLostFocus; + SizeChanged += TicketCompletion_SizeChanged; + Loaded += TicketCompletion_Loaded; + } + + protected override void OnSourceInitialized(EventArgs e) + { + base.OnSourceInitialized(e); + UpdateDialogMaxHeightToScreen(); + } + + protected override void OnLocationChanged(EventArgs e) + { + base.OnLocationChanged(e); + UpdateDialogMaxHeightToScreen(); + } + + private void TicketCompletion_Loaded(object sender, RoutedEventArgs e) => UpdateDialogMaxHeightToScreen(); + + private void TicketCompletion_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateDialogMaxHeightToScreen(); #region ClosingBusy @@ -126,98 +126,98 @@ namespace FasdDesktopUi.Pages.TicketCompletion return null; } - #region Close_Click - - private void Close_Click() - { - isCanceled = true; - TrySetDialogResult(null); - Close(); - } + #region Close_Click - private void CloseButton_Click(object sender, InputEventArgs e) => Close_Click(); - - #endregion - - private void TrySetDialogResult(bool? result) - { - try - { - DialogResult = result; - } - catch (InvalidOperationException) - { - // Window was not shown as dialog; ignore. - } - } - - private void UpdateDialogMaxHeightToScreen() - { - if (isUpdatingDialogBounds) - return; - - isUpdatingDialogBounds = true; - try - { - WinForms.Screen screen = null; - IntPtr currentHandle = new WindowInteropHelper(this).Handle; - - if (currentHandle != IntPtr.Zero) - { - screen = WinForms.Screen.FromHandle(currentHandle); - } - else if (Owner != null) - { - IntPtr ownerHandle = new WindowInteropHelper(Owner).Handle; - if (ownerHandle != IntPtr.Zero) - screen = WinForms.Screen.FromHandle(ownerHandle); - } - - screen = screen ?? WinForms.Screen.PrimaryScreen; - var workingArea = screen?.WorkingArea ?? WinForms.Screen.PrimaryScreen.WorkingArea; - var dpiScaleY = VisualTreeHelper.GetDpi(this).DpiScaleY; - var safeDpiScaleY = Math.Max(0.1, dpiScaleY); - var workingAreaTopDip = workingArea.Top / safeDpiScaleY; - var workingAreaBottomDip = workingArea.Bottom / safeDpiScaleY; - var workingAreaHeightDip = workingArea.Height / safeDpiScaleY; - var availableWindowHeightDip = workingAreaHeightDip - (WindowWorkingAreaMarginDip * 2); - - MaxHeight = Math.Max(MinWindowHeightDip, availableWindowHeightDip); - - if (!double.IsNaN(Top)) - { - var minTop = workingAreaTopDip + WindowWorkingAreaMarginDip; - var maxBottom = workingAreaBottomDip - WindowWorkingAreaMarginDip; - - if (Top < minTop) - Top = minTop; - - var currentBottom = Top + ActualHeight; - if (currentBottom > maxBottom) - Top = Math.Max(minTop, maxBottom - ActualHeight); - } - - double nonDialogReserve = DialogNonContentReserveDip; - if (CloseCaseDialogUc != null && CloseCaseDialogUc.IsLoaded) - { - var estimatedReserve = ActualHeight - CloseCaseDialogUc.ActualHeight; - if (estimatedReserve > 0) - nonDialogReserve = Math.Max(nonDialogReserve, estimatedReserve + WindowWorkingAreaMarginDip); - } - - CloseCaseDialogUc?.SetDialogContentMaxHeight(MaxHeight - nonDialogReserve); - } - catch (Exception ex) - { - LogException(ex); - } - finally - { - isUpdatingDialogBounds = false; - } - } - - #region Internal Focus Events + private void Close_Click() + { + isCanceled = true; + TrySetDialogResult(null); + Close(); + } + + private void CloseButton_Click(object sender, InputEventArgs e) => Close_Click(); + + #endregion + + private void TrySetDialogResult(bool? result) + { + try + { + DialogResult = result; + } + catch (InvalidOperationException) + { + // Window was not shown as dialog; ignore. + } + } + + private void UpdateDialogMaxHeightToScreen() + { + if (isUpdatingDialogBounds) + return; + + isUpdatingDialogBounds = true; + try + { + WinForms.Screen screen = null; + IntPtr currentHandle = new WindowInteropHelper(this).Handle; + + if (currentHandle != IntPtr.Zero) + { + screen = WinForms.Screen.FromHandle(currentHandle); + } + else if (Owner != null) + { + IntPtr ownerHandle = new WindowInteropHelper(Owner).Handle; + if (ownerHandle != IntPtr.Zero) + screen = WinForms.Screen.FromHandle(ownerHandle); + } + + screen = screen ?? WinForms.Screen.PrimaryScreen; + var workingArea = screen?.WorkingArea ?? WinForms.Screen.PrimaryScreen.WorkingArea; + var dpiScaleY = VisualTreeHelper.GetDpi(this).DpiScaleY; + var safeDpiScaleY = Math.Max(0.1, dpiScaleY); + var workingAreaTopDip = workingArea.Top / safeDpiScaleY; + var workingAreaBottomDip = workingArea.Bottom / safeDpiScaleY; + var workingAreaHeightDip = workingArea.Height / safeDpiScaleY; + var availableWindowHeightDip = workingAreaHeightDip - (WindowWorkingAreaMarginDip * 2); + + MaxHeight = Math.Max(MinWindowHeightDip, availableWindowHeightDip); + + if (!double.IsNaN(Top)) + { + var minTop = workingAreaTopDip + WindowWorkingAreaMarginDip; + var maxBottom = workingAreaBottomDip - WindowWorkingAreaMarginDip; + + if (Top < minTop) + Top = minTop; + + var currentBottom = Top + ActualHeight; + if (currentBottom > maxBottom) + Top = Math.Max(minTop, maxBottom - ActualHeight); + } + + double nonDialogReserve = DialogNonContentReserveDip; + if (CloseCaseDialogUc != null && CloseCaseDialogUc.IsLoaded) + { + var estimatedReserve = ActualHeight - CloseCaseDialogUc.ActualHeight; + if (estimatedReserve > 0) + nonDialogReserve = Math.Max(nonDialogReserve, estimatedReserve + WindowWorkingAreaMarginDip); + } + + CloseCaseDialogUc?.SetDialogContentMaxHeight(MaxHeight - nonDialogReserve); + } + catch (Exception ex) + { + LogException(ex); + } + finally + { + isUpdatingDialogBounds = false; + } + } + + #region Internal Focus Events private void ElementGotFocus(object sender, EventArgs e) { @@ -285,7 +285,14 @@ namespace FasdDesktopUi.Pages.TicketCompletion switch (e.Key) { case Key.Escape: + if (CloseCaseDialogUc?.TryHandleEscapeKey() == true) + { + e.Handled = true; + return; + } + Close_Click(); + e.Handled = true; break; } } @@ -303,15 +310,15 @@ namespace FasdDesktopUi.Pages.TicketCompletion bool closedSuccessfull = await CloseCaseDialogUc.CloseCaseAsync(_dataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.User).Id); - if (closedSuccessfull) - { - SuccessPage.SuccessPage successPage = new SuccessPage.SuccessPage(); - successPage.Show(); - await _dataProvider?.CloseCaseAsync(); - TrySetDialogResult(true); - Close(); - } - } + if (closedSuccessfull) + { + SuccessPage.SuccessPage successPage = new SuccessPage.SuccessPage(); + successPage.Show(); + await _dataProvider?.CloseCaseAsync(); + TrySetDialogResult(true); + Close(); + } + } catch (Exception E) { LogException(E);