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 CategoryTableNameLegacy = "M42Wpm-Ticket-CloseCase-Categories"; private const string TicketDetailsTableName = "M42Wpm-Tickets"; private const string TicketDetailsCategoryIdColumnName = "CategoryId"; private string activeCategoryTableName = CategoryTableNamePrimary; 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, System.ComponentModel.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; var tableCandidates = new[] { CategoryTableNamePrimary, CategoryTableNameLegacy }; bool initialized = false; foreach (var tableName in tableCandidates) { if (await TryPopulateCategoryHierarchyAsync(tableName)) { activeCategoryTableName = tableName; initialized = true; break; } } if (initialized) { 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; cF4SDHealthCardRawData.cHealthCardTableColumn parentIdColumn = null; cF4SDHealthCardRawData.cHealthCardTableColumn parentNameColumn = null; if (!dataTable.Columns.TryGetValue("parentValue", out parentIdColumn)) dataTable.Columns.TryGetValue("Parent_Value", out parentIdColumn); if (!dataTable.Columns.TryGetValue("parent", out 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: validateComboboxNotEmpty(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 static void validateComboboxNotEmpty(object sender) { //var comboBox = sender as ComboBox; //if (comboBox != null) //{ // if (!(comboBox.SelectedItem is ComboBoxItem selectedItem)) // return; // // Überprüfe den Inhalt und setze die Hintergrundfarbe entsprechend // if (selectedItem.Tag == null) // { // // Setze die Hintergrundfarbe auf Rot, um einen Validierungsfehler anzuzeigen // comboBox.BorderBrush = SharedValidationBorderBrush; // } // else // { // // Setze die ursprüngliche Hintergrundfarbe zurück, wenn die Validierung erfolgreich ist // comboBox.BorderBrush = (SolidColorBrush)new BrushConverter().ConvertFromString("#DEE2E6"); // } //} } 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; SelectedTicket.Infos[TicketInfoKeys.Summary] = CaseNotesPreview.Text; 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) { var textBox = sender as TextBox; if (textBox == null) 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 != null ? borderBrush.CloneCurrentValue() : null; } 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); } } } }