/// <summary> /// Reverts the click. /// </summary> /// <param name="obj">The object.</param> private void RevertClick(HistoricalTransaction obj) { var messageBoxResult = MessageBox.Show("Are you sure you wish to revert this transaction?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (messageBoxResult == MessageBoxResult.Yes) { using (new MouseCursor(Cursors.Wait)) { var databaseManager = new DatabaseManager(PluginSettings.DatabaseSettings); try { using (SqlCommand command = databaseManager.CreateCommand("spRevert", CommandType.StoredProcedure)) { databaseManager.AddParameter(command, "@transactionId", obj.TransactionId); command.ExecuteNonQuery( ); LoadTransactions( ); SendRequest(obj.TenantId); } } catch (Exception exc) { MessageBox.Show("Unable to revert the selected transaction(s) due to successive transactions requiring them.", "Unable to revert", MessageBoxButton.OK, MessageBoxImage.Exclamation); PluginSettings.EventLog.WriteException(exc); } } } }
/// <summary> /// Reverts to click. /// </summary> /// <param name="obj">The object.</param> private void RevertToClick(HistoricalTransaction obj) { var messageBoxResult = MessageBox.Show("Are you sure you wish to revert to this transaction?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (messageBoxResult == MessageBoxResult.Yes) { using (new MouseCursor(Cursors.Wait)) { var databaseManager = new DatabaseManager(PluginSettings.DatabaseSettings); try { ///// // Start at the next transaction since RevertTo reverts upto but not including the selected transaction. ///// HistoricalTransaction transaction = obj.NextTransaction; long tenantId = transaction.TenantId; bool multipleTenants = tenantId == -1; while (transaction != null) { if (transaction.TenantId != tenantId) { multipleTenants = true; break; } transaction = transaction.NextTransaction; } using (SqlCommand command = databaseManager.CreateCommand("spRevertTo", CommandType.StoredProcedure)) { databaseManager.AddParameter(command, "@transactionId", obj.TransactionId); if (!multipleTenants) { databaseManager.AddParameter(command, "@tenantId", tenantId); } command.ExecuteNonQuery( ); LoadTransactions( ); SendRequest(obj.TenantId); } } catch (Exception exc) { MessageBox.Show("Unable to revert the selected transaction(s) due to successive transactions requiring them.", "Unable to revert", MessageBoxButton.OK, MessageBoxImage.Exclamation); PluginSettings.EventLog.WriteException(exc); } } } }
/// <summary> /// Handles the ToolTipOpening event of the lv control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="ToolTipEventArgs" /> instance containing the event data.</param> private void lv_ToolTipOpening(object sender, ToolTipEventArgs e) { ListViewItem item = e.Source as ListViewItem; HistoricalTransaction transaction = item?.Content as HistoricalTransaction; if (transaction != null) { transaction.LoadTooltip( ); item.ToolTip = transaction.Tooltip; } }
/// <summary> /// Reverts the range tenant click. /// </summary> /// <param name="obj">The object.</param> private void RevertRangeTenantClick(Tuple <long, IList> obj) { if (obj?.Item2 == null || obj.Item2.Count <= 0) { return; } HistoricalTransaction start = obj.Item2[0] as HistoricalTransaction; HistoricalTransaction end = obj.Item2[obj.Item2.Count - 1] as HistoricalTransaction; if (start != null && end != null) { var messageBoxResult = MessageBox.Show("Are you sure you wish to revert these transactions?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (messageBoxResult == MessageBoxResult.Yes) { using (new MouseCursor(Cursors.Wait)) { var databaseManager = new DatabaseManager(PluginSettings.DatabaseSettings); try { using (SqlCommand command = databaseManager.CreateCommand("spRevertRange", CommandType.StoredProcedure)) { databaseManager.AddParameter(command, "@fromTransactionId", start.TransactionId); databaseManager.AddParameter(command, "@toTransactionId", end.TransactionId); databaseManager.AddParameter(command, "@tenantId", obj.Item1); command.ExecuteNonQuery( ); LoadTransactions( ); SendRequest(obj.Item1); } } catch (Exception exc) { MessageBox.Show("Unable to revert the selected transaction(s) due to successive transactions requiring them.", "Unable to revert", MessageBoxButton.OK, MessageBoxImage.Exclamation); PluginSettings.EventLog.WriteException(exc); } } } } }
/// <summary> /// Handles the MouseDoubleClick event of the ReadiMonListView control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs" /> instance containing the event data.</param> private void ReadiMonListView_MouseDoubleClick(object sender, MouseButtonEventArgs e) { ReadiMonListView listView = sender as ReadiMonListView; if (e.ChangedButton != MouseButton.Left) { return; } DependencyObject source = e.OriginalSource as DependencyObject; while (source != null) { FrameworkElement element = source as FrameworkElement; ListViewItem item = element?.TemplatedParent as ListViewItem; if (item?.Content is HistoricalTransaction) { break; } source = VisualTreeHelper.GetParent(source); } if (source == null) { return; } HistoricalTransaction transaction = listView?.SelectedItem as HistoricalTransaction; if (transaction != null) { HistoryViewer viewer = new HistoryViewer(transaction.TransactionId, _viewModel.PluginSettings); var helper = new WindowInteropHelper(viewer); helper.Owner = Process.GetCurrentProcess( ).MainWindowHandle; viewer.ShowDialog( ); } }
/// <summary> /// Loads the transactions. /// </summary> private void LoadTransactionsAsynchronous( ) { _dispatcher.Invoke(() => { ListViewEnabled = false; MouseCursor.Set(Cursors.Wait); PluginSettings.Channel.SendMessage(new StatusTextMessage(@"Loading transactions...").ToString( )); }); try { var databaseManager = new DatabaseManager(PluginSettings.DatabaseSettings); HashSet <long> selectedTransactions = null; if (SelectedTransactions != null) { selectedTransactions = new HashSet <long>( ); foreach (HistoricalTransaction transaction in SelectedTransactions) { selectedTransactions.Add(transaction.TransactionId); } } const string commandText = @"--ReadiMon - LoadTransactions SET NOCOUNT ON SELECT [TransactionId], [UserId], [TenantId], [Spid], [Timestamp], [HostName], [ProgramName], [Domain], [Username], [LoginName], [Context] FROM Hist_Transaction ORDER BY TransactionId DESC" ; HistoricalTransaction.TenantCache.Clear( ); HistoricalTransaction.UserCache.Clear( ); HashSet <string> users = new HashSet <string>( ); HashSet <string> tenants = new HashSet <string>( ); HashSet <string> spids = new HashSet <string>( ); HashSet <string> programs = new HashSet <string>( ); HashSet <string> logins = new HashSet <string>( ); var transactions = new List <HistoricalTransaction>( ); using (IDbCommand command = databaseManager.CreateCommand(commandText)) { using (IDataReader reader = command.ExecuteReader( )) { HistoricalTransaction previousTransaction = null; while (reader.Read( )) { var transaction = new HistoricalTransaction(reader, GetChangeCounts); transactions.Add(transaction); if (previousTransaction != null) { previousTransaction.NextTransaction = transaction; } previousTransaction = transaction; } } } const string tenantCommandText = @"-- ReadiMon - Select Tenant Names SELECT Id, name FROM _vTenant" ; using (IDbCommand command = databaseManager.CreateCommand(tenantCommandText)) { using (IDataReader reader = command.ExecuteReader( )) { while (reader.Read( )) { HistoricalTransaction.TenantCache[reader.GetInt64(0)] = reader.GetString(1); } } } HistoricalTransaction.TenantCache[0] = "Global"; const string userCommandText = @"-- ReadiMon - Select User Name SELECT dbo.fnName( @userId )" ; foreach (long userId in transactions.Select(t => t.UserId).Distinct( ).Where(t => t > 0)) { using (SqlCommand command = databaseManager.CreateCommand(userCommandText)) { databaseManager.AddParameter(command, "@userId", userId); object userName = command.ExecuteScalar( ); if (userName != null && userName != DBNull.Value) { HistoricalTransaction.UserCache[userId] = userName.ToString( ); } } } HistoricalTransaction.UserCache[0] = "Administrator"; Transactions = transactions; users.UnionWith(Transactions.Select(t => t.ActiveUserName.ToString( ))); tenants.UnionWith(Transactions.Select(t => t.TenantName.ToString( ))); spids.UnionWith(Transactions.Select(t => t.Spid.ToString( ))); programs.UnionWith(Transactions.Select(t => t.ProgramName)); logins.UnionWith(Transactions.Select(t => t.LoginName)); UserFilters = new List <FilterObject>( ); foreach (string user in users.OrderBy(k => k)) { UserFilters.Add(new FilterObject(user, string.IsNullOrEmpty(user) ? "<empty>" : user, true, UserFilterUpdate)); } OnPropertyChanged("UserFilters"); TenantFilters = new List <FilterObject>( ); foreach (string ten in tenants.OrderBy(k => k)) { TenantFilters.Add(new FilterObject(ten, string.IsNullOrEmpty(ten) ? "<empty>" : ten, true, TenantFilterUpdate)); } OnPropertyChanged("TenantFilters"); SpidFilters = new List <FilterObject>( ); foreach (string spid in spids.OrderBy(k => k)) { SpidFilters.Add(new FilterObject(spid, string.IsNullOrEmpty(spid) ? "<empty>" : spid, true, SpidFilterUpdate)); } OnPropertyChanged("SpidFilters"); ProgramFilters = new List <FilterObject>( ); foreach (string prog in programs.OrderBy(k => k)) { ProgramFilters.Add(new FilterObject(prog, string.IsNullOrEmpty(prog) ? "<empty>" : prog, true, ProgramFilterUpdate)); } OnPropertyChanged("ProgramFilters"); LoginFilters = new List <FilterObject>( ); foreach (string log in logins.OrderBy(k => k)) { LoginFilters.Add(new FilterObject(log, string.IsNullOrEmpty(log) ? "<empty>" : log, true, LoginFilterUpdate)); } OnPropertyChanged("LoginFilters"); FilteredTransactions = new List <HistoricalTransaction>(Transactions); if (selectedTransactions != null) { List <HistoricalTransaction> newlySelectedTransactions = FilteredTransactions.Where(t => selectedTransactions.Contains(t.TransactionId)).ToList( ); SelectedTransactions = newlySelectedTransactions; } } catch (Exception exc) { PluginSettings.EventLog.WriteException(exc); } finally { _dispatcher.Invoke(() => { ListViewEnabled = true; MouseCursor.Set(Cursors.Arrow); PluginSettings.Channel.SendMessage(new StatusTextMessage(@"Ready...").ToString( )); }); } }
/// <summary> /// Reverts the selected click. /// </summary> /// <param name="obj">The object.</param> private void RevertSelectedClick(IList obj) { if (obj == null || obj.Count <= 0) { return; } ISet <long> transactions = new HashSet <long>( ); HistoricalTransaction firstTransaction = null; foreach (HistoricalTransaction transaction in obj) { transactions.Add(transaction.TransactionId); if (firstTransaction == null) { firstTransaction = transaction; } } if (transactions.Count > 0) { var messageBoxResult = MessageBox.Show("Are you sure you wish to revert the selected transactions?", "Confirm", MessageBoxButton.YesNo, MessageBoxImage.Warning); if (messageBoxResult == MessageBoxResult.Yes) { using (new MouseCursor(Cursors.Wait)) { var databaseManager = new DatabaseManager(PluginSettings.DatabaseSettings); var sqlTransaction = databaseManager.BeginTransaction( ); try { using (SqlCommand command = databaseManager.CreateCommand("spRevert", CommandType.StoredProcedure, 30000, sqlTransaction)) { var parameter = databaseManager.AddParameter(command, "@transactionId", SqlDbType.BigInt); databaseManager.AddParameter(command, "@context", SqlDbType.VarChar, $"Reverting transactions {string.Join( ",", transactions.OrderByDescending( t => t ) )}"); foreach (long transactionId in transactions.OrderByDescending(t => t)) { parameter.Value = transactionId; command.ExecuteNonQuery( ); } sqlTransaction.Commit( ); LoadTransactions( ); if (firstTransaction != null) { SendRequest(firstTransaction.TenantId); } } } catch (Exception exc) { sqlTransaction.Rollback( ); MessageBox.Show("Unable to revert the selected transaction(s) due to successive transactions requiring them.", "Unable to revert", MessageBoxButton.OK, MessageBoxImage.Exclamation); PluginSettings.EventLog.WriteException(exc); } } } } }
/// <summary> /// Handles the SelectionChanged event of the ReadiMonListView control. /// </summary> /// <param name="sender">The source of the event.</param> /// <param name="e">The <see cref="SelectionChangedEventArgs" /> instance containing the event data.</param> private void ReadiMonListView_SelectionChanged(object sender, SelectionChangedEventArgs e) { ReadiMonListView listView = sender as ReadiMonListView; if (listView == null) { return; } HistoryContextMenu.Items.Clear( ); if (listView.SelectedItems == null || listView.SelectedItems.Count <= 0) { return; } if (listView.SelectedItems.Count == 1) { MenuItem revertItem = new MenuItem { Header = "Revert", Command = _viewModel.RevertCommand, CommandParameter = listView.SelectedItems[0] }; HistoryContextMenu.Items.Add(revertItem); HistoricalTransaction transaction = listView.SelectedItems[0] as HistoricalTransaction; ///// // Only show RevertTo if the selected transaction is NOT the last transaction in the list ///// if (transaction?.NextTransaction != null) { MenuItem revertToItem = new MenuItem { Header = "Revert To", Command = _viewModel.RevertToCommand, CommandParameter = listView.SelectedItems[0] }; HistoryContextMenu.Items.Add(revertToItem); } Dictionary <string, long> tenantMap = new Dictionary <string, long>( ); HashSet <string> tenantNames = new HashSet <string>( ); transaction = transaction?.NextTransaction; while (transaction != null) { ///// // If any transaction is for tenant -1 (multiple tenants) do not show specific RevertTo entries. ///// if (transaction.TenantId == -1) { tenantNames.Clear( ); tenantMap.Clear( ); break; } tenantNames.Add(transaction.TenantName); tenantMap[transaction.TenantName] = transaction.TenantId; transaction = transaction.NextTransaction; } if (tenantNames.Count > 1) { foreach (string tenantName in tenantNames.OrderBy(t => t)) { MenuItem revertToTenantItem = new MenuItem { Header = $"Revert To ({tenantName} tenant only)", Command = _viewModel.RevertToTenantCommand, CommandParameter = new Tuple <long, HistoricalTransaction>(tenantMap[tenantName], listView.SelectedItems[0] as HistoricalTransaction) }; HistoryContextMenu.Items.Add(revertToTenantItem); } } } else { List <HistoricalTransaction> sortedList = new List <HistoricalTransaction>( ); foreach (HistoricalTransaction transaction in listView.SelectedItems) { sortedList.Add(transaction); } sortedList.Sort((a, b) => a.TransactionId.CompareTo(b.TransactionId)); bool consecutive = true; for (int i = 0; i < sortedList.Count - 1; i++) { HistoricalTransaction transactionA = sortedList[i]; HistoricalTransaction transactionB = sortedList[i + 1]; if (transactionA != null && transactionA.NextTransaction != transactionB) { consecutive = false; break; } } if (consecutive) { MenuItem revertRangeItem = new MenuItem { Header = "Revert Range", Command = _viewModel.RevertRangeCommand, CommandParameter = listView.SelectedItems }; HistoryContextMenu.Items.Add(revertRangeItem); HashSet <string> tenantNames = new HashSet <string>( ); Dictionary <string, long> tenantMap = new Dictionary <string, long>( ); foreach (HistoricalTransaction transaction in listView.SelectedItems) { tenantNames.Add(transaction.TenantName); tenantMap[transaction.TenantName] = transaction.TenantId; } if (tenantNames.Count > 1) { foreach (string tenantName in tenantNames.OrderBy(t => t)) { MenuItem revertToTenantItem = new MenuItem { Header = $"Revert Range ({tenantName} tenant only)", Command = _viewModel.RevertRangeTenantCommand, CommandParameter = new Tuple <long, IList>(tenantMap[tenantName], listView.SelectedItems) }; HistoryContextMenu.Items.Add(revertToTenantItem); } } } else { MenuItem revertSelectedItem = new MenuItem { Header = "Revert Selected", Command = _viewModel.RevertSelectedCommand, CommandParameter = listView.SelectedItems }; HistoryContextMenu.Items.Add(revertSelectedItem); HashSet <string> tenantNames = new HashSet <string>( ); Dictionary <string, long> tenantMap = new Dictionary <string, long>( ); foreach (HistoricalTransaction transaction in listView.SelectedItems) { tenantNames.Add(transaction.TenantName); tenantMap[transaction.TenantName] = transaction.TenantId; } if (tenantNames.Count > 1) { foreach (string tenantName in tenantNames.OrderBy(t => t)) { MenuItem revertToTenantItem = new MenuItem { Header = $"Revert Selected ({tenantName} tenant only)", Command = _viewModel.RevertSelectedTenantCommand, CommandParameter = new Tuple <long, IList>(tenantMap[tenantName], listView.SelectedItems) }; HistoryContextMenu.Items.Add(revertToTenantItem); } } } } }