# HG changeset patch # User Brad Greco # Date 1549849886 18000 # Node ID 3142e52cbe69c9799d0e9eecd1a2ef59f9a4a459 # Parent 96f0b028176d9ffba82be4a8482f75ab4d45e791 Lots more progress diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/App.config --- a/ServerMonitor/App.config Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/App.config Sun Feb 10 20:51:26 2019 -0500 @@ -2,6 +2,7 @@ +
@@ -9,6 +10,23 @@ + + + True + + + FlashTaskbar + + + NotificationBalloon + + + NotificationBalloon + + + 0 + + True diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Controls/CheckControl.cs --- a/ServerMonitor/Controls/CheckControl.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Controls/CheckControl.cs Sun Feb 10 20:51:26 2019 -0500 @@ -13,7 +13,7 @@ /// This control should never be used directly, but marking it abstract causes problems with the designer. public partial class CheckControl : UserControl { - public Type CheckType { get { return GetCheckType(GetType()); } } + public Type CheckType => GetCheckType(GetType()); public CheckControl() { diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Controls/ServerSummaryControl.Designer.cs --- a/ServerMonitor/Controls/ServerSummaryControl.Designer.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Controls/ServerSummaryControl.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -30,7 +30,9 @@ { this.ServerNameLabel = new System.Windows.Forms.Label(); this.ServerPictureBox = new System.Windows.Forms.PictureBox(); + this.StatusPictureBox = new System.Windows.Forms.PictureBox(); ((System.ComponentModel.ISupportInitialize)(this.ServerPictureBox)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.StatusPictureBox)).BeginInit(); this.SuspendLayout(); // // ServerNameLabel @@ -54,16 +56,29 @@ this.ServerPictureBox.TabIndex = 0; this.ServerPictureBox.TabStop = false; // + // StatusPictureBox + // + this.StatusPictureBox.BackColor = System.Drawing.Color.Transparent; + this.StatusPictureBox.Image = global::ServerMonitorApp.Properties.Resources.pass; + this.StatusPictureBox.Location = new System.Drawing.Point(104, 92); + this.StatusPictureBox.Name = "StatusPictureBox"; + this.StatusPictureBox.Size = new System.Drawing.Size(32, 32); + this.StatusPictureBox.TabIndex = 2; + this.StatusPictureBox.TabStop = false; + this.StatusPictureBox.Click += new System.EventHandler(this.Control_Click); + // // ServerSummaryControl // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.BackColor = System.Drawing.SystemColors.Control; + this.Controls.Add(this.StatusPictureBox); this.Controls.Add(this.ServerNameLabel); this.Controls.Add(this.ServerPictureBox); this.Name = "ServerSummaryControl"; this.Size = new System.Drawing.Size(192, 192); ((System.ComponentModel.ISupportInitialize)(this.ServerPictureBox)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.StatusPictureBox)).EndInit(); this.ResumeLayout(false); } @@ -72,5 +87,6 @@ private System.Windows.Forms.PictureBox ServerPictureBox; private System.Windows.Forms.Label ServerNameLabel; + private System.Windows.Forms.PictureBox StatusPictureBox; } } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Controls/ServerSummaryControl.cs --- a/ServerMonitor/Controls/ServerSummaryControl.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Controls/ServerSummaryControl.cs Sun Feb 10 20:51:26 2019 -0500 @@ -26,6 +26,14 @@ } Server = server; ServerNameLabel.Text = Server.Name; + StatusPictureBox.Parent = ServerPictureBox; + StatusPictureBox.Image = Server.Status.GetIcon(); + } + + public override void Refresh() + { + StatusPictureBox.Image = Server.Status.GetIcon(); + base.Refresh(); } private void Control_Click(object sender, EventArgs e) diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Controls/ServerSummaryControl.resx --- a/ServerMonitor/Controls/ServerSummaryControl.resx Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Controls/ServerSummaryControl.resx Sun Feb 10 20:51:26 2019 -0500 @@ -112,9 +112,9 @@ 2.0 - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/CheckForm.Designer.cs --- a/ServerMonitor/Forms/CheckForm.Designer.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/CheckForm.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -33,6 +33,8 @@ this.CheckTypePanel = new System.Windows.Forms.Panel(); this.TypeHelpPictureBox = new System.Windows.Forms.PictureBox(); this.GeneralGroupBox = new System.Windows.Forms.GroupBox(); + this.SeverityComboBox = new System.Windows.Forms.ComboBox(); + this.SeverityLabel = new System.Windows.Forms.Label(); this.ScheduleAtPanel = new System.Windows.Forms.Panel(); this.AtTimePicker = new System.Windows.Forms.DateTimePicker(); this.ScheduleAtLabel = new System.Windows.Forms.Label(); @@ -93,7 +95,7 @@ this.CheckTypePanel.Controls.Add(this.CheckTypeLabel); this.CheckTypePanel.Controls.Add(this.TypeHelpPictureBox); this.CheckTypePanel.Controls.Add(this.CheckTypeComboBox); - this.CheckTypePanel.Location = new System.Drawing.Point(162, 12); + this.CheckTypePanel.Location = new System.Drawing.Point(167, 12); this.CheckTypePanel.Name = "CheckTypePanel"; this.CheckTypePanel.Size = new System.Drawing.Size(227, 26); this.CheckTypePanel.TabIndex = 1; @@ -114,6 +116,8 @@ // this.GeneralGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); + this.GeneralGroupBox.Controls.Add(this.SeverityComboBox); + this.GeneralGroupBox.Controls.Add(this.SeverityLabel); this.GeneralGroupBox.Controls.Add(this.ScheduleAtPanel); this.GeneralGroupBox.Controls.Add(this.ScheduleBetweenPanel); this.GeneralGroupBox.Controls.Add(this.FrequencyUnitsComboBox); @@ -127,16 +131,34 @@ this.GeneralGroupBox.Controls.Add(this.EnabledCheckBox); this.GeneralGroupBox.Location = new System.Drawing.Point(12, 39); this.GeneralGroupBox.Name = "GeneralGroupBox"; - this.GeneralGroupBox.Size = new System.Drawing.Size(526, 115); + this.GeneralGroupBox.Size = new System.Drawing.Size(537, 135); this.GeneralGroupBox.TabIndex = 2; this.GeneralGroupBox.TabStop = false; this.GeneralGroupBox.Text = "General settings"; // + // SeverityComboBox + // + this.SeverityComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.SeverityComboBox.FormattingEnabled = true; + this.SeverityComboBox.Location = new System.Drawing.Point(92, 106); + this.SeverityComboBox.Name = "SeverityComboBox"; + this.SeverityComboBox.Size = new System.Drawing.Size(82, 21); + this.SeverityComboBox.TabIndex = 34; + // + // SeverityLabel + // + this.SeverityLabel.AutoSize = true; + this.SeverityLabel.Location = new System.Drawing.Point(6, 109); + this.SeverityLabel.Name = "SeverityLabel"; + this.SeverityLabel.Size = new System.Drawing.Size(80, 13); + this.SeverityLabel.TabIndex = 33; + this.SeverityLabel.Text = "Failure severity:"; + // // ScheduleAtPanel // this.ScheduleAtPanel.Controls.Add(this.AtTimePicker); this.ScheduleAtPanel.Controls.Add(this.ScheduleAtLabel); - this.ScheduleAtPanel.Location = new System.Drawing.Point(247, 76); + this.ScheduleAtPanel.Location = new System.Drawing.Point(258, 76); this.ScheduleAtPanel.Name = "ScheduleAtPanel"; this.ScheduleAtPanel.Size = new System.Drawing.Size(270, 29); this.ScheduleAtPanel.TabIndex = 32; @@ -167,7 +189,7 @@ this.ScheduleBetweenPanel.Controls.Add(this.EndTimePicker); this.ScheduleBetweenPanel.Controls.Add(this.StartTimePicker); this.ScheduleBetweenPanel.Controls.Add(this.ScheduleBetweenLabel); - this.ScheduleBetweenPanel.Location = new System.Drawing.Point(247, 76); + this.ScheduleBetweenPanel.Location = new System.Drawing.Point(258, 76); this.ScheduleBetweenPanel.Name = "ScheduleBetweenPanel"; this.ScheduleBetweenPanel.Size = new System.Drawing.Size(270, 29); this.ScheduleBetweenPanel.TabIndex = 31; @@ -214,7 +236,7 @@ // this.FrequencyUnitsComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; this.FrequencyUnitsComboBox.FormattingEnabled = true; - this.FrequencyUnitsComboBox.Location = new System.Drawing.Point(169, 79); + this.FrequencyUnitsComboBox.Location = new System.Drawing.Point(180, 79); this.FrequencyUnitsComboBox.Name = "FrequencyUnitsComboBox"; this.FrequencyUnitsComboBox.Size = new System.Drawing.Size(75, 21); this.FrequencyUnitsComboBox.TabIndex = 30; @@ -224,7 +246,7 @@ // ScheduleEveryLabel // this.ScheduleEveryLabel.AutoSize = true; - this.ScheduleEveryLabel.Location = new System.Drawing.Point(78, 82); + this.ScheduleEveryLabel.Location = new System.Drawing.Point(89, 82); this.ScheduleEveryLabel.Name = "ScheduleEveryLabel"; this.ScheduleEveryLabel.Size = new System.Drawing.Size(34, 13); this.ScheduleEveryLabel.TabIndex = 29; @@ -232,7 +254,7 @@ // // FrequencyUpDown // - this.FrequencyUpDown.Location = new System.Drawing.Point(114, 80); + this.FrequencyUpDown.Location = new System.Drawing.Point(125, 80); this.FrequencyUpDown.Maximum = new decimal(new int[] { 59, 0, @@ -254,7 +276,7 @@ 0, 0, 0}); - this.TimeoutInput.Location = new System.Drawing.Point(81, 54); + this.TimeoutInput.Location = new System.Drawing.Point(92, 54); this.TimeoutInput.Maximum = new decimal(new int[] { 60000, 0, @@ -277,7 +299,7 @@ // PingTimeoutLabel // this.PingTimeoutLabel.AutoSize = true; - this.PingTimeoutLabel.Location = new System.Drawing.Point(5, 56); + this.PingTimeoutLabel.Location = new System.Drawing.Point(6, 56); this.PingTimeoutLabel.Name = "PingTimeoutLabel"; this.PingTimeoutLabel.Size = new System.Drawing.Size(70, 13); this.PingTimeoutLabel.TabIndex = 26; @@ -303,7 +325,7 @@ // // NameTextBox // - this.NameTextBox.Location = new System.Drawing.Point(81, 28); + this.NameTextBox.Location = new System.Drawing.Point(92, 28); this.NameTextBox.Name = "NameTextBox"; this.NameTextBox.Size = new System.Drawing.Size(181, 20); this.NameTextBox.TabIndex = 22; @@ -313,7 +335,7 @@ this.EnabledCheckBox.AutoSize = true; this.EnabledCheckBox.Checked = true; this.EnabledCheckBox.CheckState = System.Windows.Forms.CheckState.Checked; - this.EnabledCheckBox.Location = new System.Drawing.Point(268, 31); + this.EnabledCheckBox.Location = new System.Drawing.Point(279, 31); this.EnabledCheckBox.Name = "EnabledCheckBox"; this.EnabledCheckBox.Size = new System.Drawing.Size(65, 17); this.EnabledCheckBox.TabIndex = 23; @@ -324,7 +346,7 @@ // this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.OkButton.DialogResult = System.Windows.Forms.DialogResult.OK; - this.OkButton.Location = new System.Drawing.Point(382, 397); + this.OkButton.Location = new System.Drawing.Point(393, 397); this.OkButton.Name = "OkButton"; this.OkButton.Size = new System.Drawing.Size(75, 23); this.OkButton.TabIndex = 20; @@ -336,7 +358,7 @@ // this.CancelCheckButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); this.CancelCheckButton.DialogResult = System.Windows.Forms.DialogResult.Cancel; - this.CancelCheckButton.Location = new System.Drawing.Point(463, 397); + this.CancelCheckButton.Location = new System.Drawing.Point(474, 397); this.CancelCheckButton.Name = "CancelCheckButton"; this.CancelCheckButton.Size = new System.Drawing.Size(75, 23); this.CancelCheckButton.TabIndex = 19; @@ -349,9 +371,9 @@ this.CheckSettingsPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); - this.CheckSettingsPanel.Location = new System.Drawing.Point(12, 160); + this.CheckSettingsPanel.Location = new System.Drawing.Point(12, 180); this.CheckSettingsPanel.Name = "CheckSettingsPanel"; - this.CheckSettingsPanel.Size = new System.Drawing.Size(526, 231); + this.CheckSettingsPanel.Size = new System.Drawing.Size(537, 211); this.CheckSettingsPanel.TabIndex = 27; // // ResultLabel @@ -361,7 +383,7 @@ this.ResultLabel.AutoEllipsis = true; this.ResultLabel.Location = new System.Drawing.Point(115, 394); this.ResultLabel.Name = "ResultLabel"; - this.ResultLabel.Size = new System.Drawing.Size(261, 29); + this.ResultLabel.Size = new System.Drawing.Size(272, 29); this.ResultLabel.TabIndex = 29; this.ResultLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; this.ResultLabel.Visible = false; @@ -410,7 +432,7 @@ this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.CancelButton = this.CancelCheckButton; - this.ClientSize = new System.Drawing.Size(550, 432); + this.ClientSize = new System.Drawing.Size(561, 432); this.Controls.Add(this.ResultIconPictureBox); this.Controls.Add(this.ResultLabel); this.Controls.Add(this.CancelRunButton); @@ -472,5 +494,7 @@ private System.Windows.Forms.Panel ScheduleAtPanel; private System.Windows.Forms.DateTimePicker AtTimePicker; private System.Windows.Forms.Label ScheduleAtLabel; + private System.Windows.Forms.ComboBox SeverityComboBox; + private System.Windows.Forms.Label SeverityLabel; } } \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/CheckForm.cs --- a/ServerMonitor/Forms/CheckForm.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/CheckForm.cs Sun Feb 10 20:51:26 2019 -0500 @@ -28,7 +28,7 @@ public int CheckId { get; private set; } - public Point HelpLocation { get { return TypeHelpPictureBox.PointToScreen(Point.Empty); } } + public Point HelpLocation => TypeHelpPictureBox.PointToScreen(Point.Empty); public CheckForm(ServerMonitor monitor, Check check) { @@ -50,6 +50,8 @@ private void CheckForm_Load(object sender, EventArgs e) { CheckTypeComboBox.Items.AddRange(Check.CheckTypes); + SeverityComboBox.Items.AddRange(new object[] { CheckStatus.Error, CheckStatus.Warning, CheckStatus.Information }); + SeverityComboBox.SelectedIndex = 0; FrequencyUnitsComboBox.DataSource = Enum.GetValues(typeof(FrequencyUnits)); Helpers.FormatImageButton(RunButton); Helpers.FormatImageButton(CancelRunButton); @@ -115,6 +117,7 @@ NameTextBox.Text = Check.Name; EnabledCheckBox.Checked = check.Enabled; TimeoutInput.Value = check.Timeout; + SeverityComboBox.SelectedItem = check.FailStatus; FrequencyUnitsComboBox.SelectedItem = check.Schedule.Units; FrequencyUpDown.Value = check.Schedule.Frequency; StartTimePicker.Value = new DateTime(1970, 1, 1) + check.Schedule.StartTime; @@ -136,6 +139,7 @@ check.Name = NameTextBox.Text; check.Enabled = EnabledCheckBox.Checked; check.Timeout = (int)TimeoutInput.Value; + check.FailStatus = (CheckStatus)SeverityComboBox.SelectedItem; check.Schedule = new Schedule((FrequencyUnits)FrequencyUnitsComboBox.SelectedItem, (int)FrequencyUpDown.Value, StartTimePicker.Value.TimeOfDay, EndTimePicker.Value.TimeOfDay); try { diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/ServerForm.Designer.cs --- a/ServerMonitor/Forms/ServerForm.Designer.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/ServerForm.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -47,6 +47,12 @@ this.KeyBrowseButton = new System.Windows.Forms.Button(); this.PasswordTextBox = new System.Windows.Forms.TextBox(); this.CheckGrid = new System.Windows.Forms.DataGridView(); + this.StatusColumn = new System.Windows.Forms.DataGridViewImageColumn(); + this.NameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ScheduleColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.LastRunTimeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.EnabledColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn(); + this.CheckBindingSource = new System.Windows.Forms.BindingSource(this.components); this.CheckActionsDividerLabel = new System.Windows.Forms.Label(); this.RunAllButton = new System.Windows.Forms.Button(); this.RunButton = new System.Windows.Forms.Button(); @@ -63,33 +69,27 @@ this.LogCheckLabel = new System.Windows.Forms.Label(); this.LogCheckComboBox = new System.Windows.Forms.ComboBox(); this.LogGrid = new System.Windows.Forms.DataGridView(); - this.dataGridViewImageColumn1 = new System.Windows.Forms.DataGridViewImageColumn(); - this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ServerInfoPanel = new System.Windows.Forms.Panel(); - this.dataGridViewImageColumn2 = new System.Windows.Forms.DataGridViewImageColumn(); - this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.LastRunTimeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.EnabledColumn = new System.Windows.Forms.DataGridViewCheckBoxColumn(); - this.dataGridViewImageColumn3 = new System.Windows.Forms.DataGridViewImageColumn(); - this.dataGridViewTextBoxColumn3 = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.StatusColumn = new System.Windows.Forms.DataGridViewImageColumn(); - this.NameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.ScheduleColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); - this.CheckBindingSource = new System.Windows.Forms.BindingSource(this.components); this.LogStatusColumn = new System.Windows.Forms.DataGridViewImageColumn(); this.LogNameColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.LogMessageColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.LogStartTimeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.LogEndTimeColumn = new System.Windows.Forms.DataGridViewTextBoxColumn(); this.CheckResultBindingSource = new System.Windows.Forms.BindingSource(this.components); + this.dataGridViewImageColumn1 = new System.Windows.Forms.DataGridViewImageColumn(); + this.dataGridViewTextBoxColumn1 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.ServerInfoPanel = new System.Windows.Forms.Panel(); + this.dataGridViewImageColumn2 = new System.Windows.Forms.DataGridViewImageColumn(); + this.dataGridViewTextBoxColumn2 = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.dataGridViewImageColumn3 = new System.Windows.Forms.DataGridViewImageColumn(); + this.dataGridViewTextBoxColumn3 = new System.Windows.Forms.DataGridViewTextBoxColumn(); ((System.ComponentModel.ISupportInitialize)(this.CheckGrid)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.CheckBindingSource)).BeginInit(); this.CheckTabControl.SuspendLayout(); this.CheckTabPage.SuspendLayout(); this.LogTabPage.SuspendLayout(); ((System.ComponentModel.ISupportInitialize)(this.LogGrid)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.CheckResultBindingSource)).BeginInit(); this.ServerInfoPanel.SuspendLayout(); - ((System.ComponentModel.ISupportInitialize)(this.CheckBindingSource)).BeginInit(); - ((System.ComponentModel.ISupportInitialize)(this.CheckResultBindingSource)).BeginInit(); this.SuspendLayout(); // // TitleLabel @@ -188,7 +188,7 @@ // // KeyTextBox // - this.KeyTextBox.Location = new System.Drawing.Point(143, 82); + this.KeyTextBox.Location = new System.Drawing.Point(147, 82); this.KeyTextBox.Name = "KeyTextBox"; this.KeyTextBox.Size = new System.Drawing.Size(202, 20); this.KeyTextBox.TabIndex = 13; @@ -211,6 +211,7 @@ this.KeyBrowseButton.TabIndex = 15; this.KeyBrowseButton.Text = "Browse..."; this.KeyBrowseButton.UseVisualStyleBackColor = true; + this.KeyBrowseButton.Click += new System.EventHandler(this.KeyBrowseButton_Click); // // PasswordTextBox // @@ -257,6 +258,57 @@ this.CheckGrid.SelectionChanged += new System.EventHandler(this.CheckGrid_SelectionChanged); this.CheckGrid.KeyDown += new System.Windows.Forms.KeyEventHandler(this.CheckGrid_KeyDown); // + // StatusColumn + // + this.StatusColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; + this.StatusColumn.DataPropertyName = "Status"; + this.StatusColumn.HeaderText = ""; + this.StatusColumn.ImageLayout = System.Windows.Forms.DataGridViewImageCellLayout.Zoom; + this.StatusColumn.Name = "StatusColumn"; + this.StatusColumn.ReadOnly = true; + this.StatusColumn.ToolTipText = "Last Run Status"; + this.StatusColumn.Width = 25; + // + // NameColumn + // + this.NameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; + this.NameColumn.DataPropertyName = "Name"; + this.NameColumn.HeaderText = "Name"; + this.NameColumn.Name = "NameColumn"; + this.NameColumn.ReadOnly = true; + this.NameColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + this.NameColumn.Width = 41; + // + // ScheduleColumn + // + this.ScheduleColumn.DataPropertyName = "Schedule"; + this.ScheduleColumn.HeaderText = "Schedule"; + this.ScheduleColumn.Name = "ScheduleColumn"; + this.ScheduleColumn.ReadOnly = true; + this.ScheduleColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // LastRunTimeColumn + // + this.LastRunTimeColumn.DataPropertyName = "LastRunTime"; + this.LastRunTimeColumn.HeaderText = "LastRunTime"; + this.LastRunTimeColumn.Name = "LastRunTimeColumn"; + this.LastRunTimeColumn.ReadOnly = true; + this.LastRunTimeColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; + // + // EnabledColumn + // + this.EnabledColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; + this.EnabledColumn.DataPropertyName = "Enabled"; + this.EnabledColumn.HeaderText = "Enabled"; + this.EnabledColumn.Name = "EnabledColumn"; + this.EnabledColumn.ReadOnly = true; + this.EnabledColumn.Width = 50; + // + // CheckBindingSource + // + this.CheckBindingSource.DataSource = typeof(ServerMonitorApp.Check); + this.CheckBindingSource.ListChanged += new System.ComponentModel.ListChangedEventHandler(this.CheckBindingSource_ListChanged); + // // CheckActionsDividerLabel // this.CheckActionsDividerLabel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); @@ -490,6 +542,57 @@ this.LogGrid.TabIndex = 28; this.LogGrid.CellFormatting += new System.Windows.Forms.DataGridViewCellFormattingEventHandler(this.LogGrid_CellFormatting); // + // LogStatusColumn + // + this.LogStatusColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; + this.LogStatusColumn.DataPropertyName = "CheckStatus"; + this.LogStatusColumn.HeaderText = ""; + this.LogStatusColumn.ImageLayout = System.Windows.Forms.DataGridViewImageCellLayout.Zoom; + this.LogStatusColumn.Name = "LogStatusColumn"; + this.LogStatusColumn.ReadOnly = true; + this.LogStatusColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True; + this.LogStatusColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; + this.LogStatusColumn.ToolTipText = "Status"; + this.LogStatusColumn.Width = 25; + // + // LogNameColumn + // + this.LogNameColumn.DataPropertyName = "Check"; + this.LogNameColumn.HeaderText = "Check"; + this.LogNameColumn.Name = "LogNameColumn"; + this.LogNameColumn.ReadOnly = true; + // + // LogMessageColumn + // + this.LogMessageColumn.DataPropertyName = "Message"; + this.LogMessageColumn.HeaderText = "Message"; + this.LogMessageColumn.Name = "LogMessageColumn"; + this.LogMessageColumn.ReadOnly = true; + // + // LogStartTimeColumn + // + this.LogStartTimeColumn.DataPropertyName = "StartTime"; + dataGridViewCellStyle1.Format = "G"; + dataGridViewCellStyle1.NullValue = null; + this.LogStartTimeColumn.DefaultCellStyle = dataGridViewCellStyle1; + this.LogStartTimeColumn.HeaderText = "StartTime"; + this.LogStartTimeColumn.Name = "LogStartTimeColumn"; + this.LogStartTimeColumn.ReadOnly = true; + // + // LogEndTimeColumn + // + this.LogEndTimeColumn.DataPropertyName = "EndTime"; + dataGridViewCellStyle2.Format = "G"; + dataGridViewCellStyle2.NullValue = null; + this.LogEndTimeColumn.DefaultCellStyle = dataGridViewCellStyle2; + this.LogEndTimeColumn.HeaderText = "EndTime"; + this.LogEndTimeColumn.Name = "LogEndTimeColumn"; + this.LogEndTimeColumn.ReadOnly = true; + // + // CheckResultBindingSource + // + this.CheckResultBindingSource.DataSource = typeof(ServerMonitorApp.CheckResult); + // // dataGridViewImageColumn1 // this.dataGridViewImageColumn1.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; @@ -550,23 +653,6 @@ this.dataGridViewTextBoxColumn2.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; this.dataGridViewTextBoxColumn2.Width = 267; // - // LastRunTimeColumn - // - this.LastRunTimeColumn.DataPropertyName = "LastRunTime"; - this.LastRunTimeColumn.HeaderText = "LastRunTime"; - this.LastRunTimeColumn.Name = "LastRunTimeColumn"; - this.LastRunTimeColumn.ReadOnly = true; - this.LastRunTimeColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // EnabledColumn - // - this.EnabledColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.EnabledColumn.DataPropertyName = "Enabled"; - this.EnabledColumn.HeaderText = "Enabled"; - this.EnabledColumn.Name = "EnabledColumn"; - this.EnabledColumn.ReadOnly = true; - this.EnabledColumn.Width = 50; - // // dataGridViewImageColumn3 // this.dataGridViewImageColumn3.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; @@ -587,91 +673,6 @@ this.dataGridViewTextBoxColumn3.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; this.dataGridViewTextBoxColumn3.Width = 267; // - // StatusColumn - // - this.StatusColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.StatusColumn.DataPropertyName = "Status"; - this.StatusColumn.HeaderText = ""; - this.StatusColumn.ImageLayout = System.Windows.Forms.DataGridViewImageCellLayout.Zoom; - this.StatusColumn.Name = "StatusColumn"; - this.StatusColumn.ReadOnly = true; - this.StatusColumn.ToolTipText = "Last Run Status"; - this.StatusColumn.Width = 25; - // - // NameColumn - // - this.NameColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells; - this.NameColumn.DataPropertyName = "Name"; - this.NameColumn.HeaderText = "Name"; - this.NameColumn.Name = "NameColumn"; - this.NameColumn.ReadOnly = true; - this.NameColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - this.NameColumn.Width = 41; - // - // ScheduleColumn - // - this.ScheduleColumn.DataPropertyName = "Schedule"; - this.ScheduleColumn.HeaderText = "Schedule"; - this.ScheduleColumn.Name = "ScheduleColumn"; - this.ScheduleColumn.ReadOnly = true; - this.ScheduleColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.NotSortable; - // - // CheckBindingSource - // - this.CheckBindingSource.DataSource = typeof(ServerMonitorApp.Check); - this.CheckBindingSource.ListChanged += new System.ComponentModel.ListChangedEventHandler(this.CheckBindingSource_ListChanged); - // - // LogStatusColumn - // - this.LogStatusColumn.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None; - this.LogStatusColumn.DataPropertyName = "CheckStatus"; - this.LogStatusColumn.HeaderText = ""; - this.LogStatusColumn.ImageLayout = System.Windows.Forms.DataGridViewImageCellLayout.Zoom; - this.LogStatusColumn.Name = "LogStatusColumn"; - this.LogStatusColumn.ReadOnly = true; - this.LogStatusColumn.Resizable = System.Windows.Forms.DataGridViewTriState.True; - this.LogStatusColumn.SortMode = System.Windows.Forms.DataGridViewColumnSortMode.Automatic; - this.LogStatusColumn.ToolTipText = "Status"; - this.LogStatusColumn.Width = 25; - // - // LogNameColumn - // - this.LogNameColumn.DataPropertyName = "Check"; - this.LogNameColumn.HeaderText = "Check"; - this.LogNameColumn.Name = "LogNameColumn"; - this.LogNameColumn.ReadOnly = true; - // - // LogMessageColumn - // - this.LogMessageColumn.DataPropertyName = "Message"; - this.LogMessageColumn.HeaderText = "Message"; - this.LogMessageColumn.Name = "LogMessageColumn"; - this.LogMessageColumn.ReadOnly = true; - // - // LogStartTimeColumn - // - this.LogStartTimeColumn.DataPropertyName = "StartTime"; - dataGridViewCellStyle1.Format = "G"; - dataGridViewCellStyle1.NullValue = null; - this.LogStartTimeColumn.DefaultCellStyle = dataGridViewCellStyle1; - this.LogStartTimeColumn.HeaderText = "StartTime"; - this.LogStartTimeColumn.Name = "LogStartTimeColumn"; - this.LogStartTimeColumn.ReadOnly = true; - // - // LogEndTimeColumn - // - this.LogEndTimeColumn.DataPropertyName = "EndTime"; - dataGridViewCellStyle2.Format = "G"; - dataGridViewCellStyle2.NullValue = null; - this.LogEndTimeColumn.DefaultCellStyle = dataGridViewCellStyle2; - this.LogEndTimeColumn.HeaderText = "EndTime"; - this.LogEndTimeColumn.Name = "LogEndTimeColumn"; - this.LogEndTimeColumn.ReadOnly = true; - // - // CheckResultBindingSource - // - this.CheckResultBindingSource.DataSource = typeof(ServerMonitorApp.CheckResult); - // // ServerForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); @@ -683,18 +684,19 @@ this.MinimumSize = new System.Drawing.Size(515, 38); this.Name = "ServerForm"; this.Text = "New Server"; + this.Activated += new System.EventHandler(this.ServerForm_Activated); this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ServerForm_FormClosing); this.Load += new System.EventHandler(this.ServerForm_Load); ((System.ComponentModel.ISupportInitialize)(this.CheckGrid)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.CheckBindingSource)).EndInit(); this.CheckTabControl.ResumeLayout(false); this.CheckTabPage.ResumeLayout(false); this.LogTabPage.ResumeLayout(false); this.LogTabPage.PerformLayout(); ((System.ComponentModel.ISupportInitialize)(this.LogGrid)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.CheckResultBindingSource)).EndInit(); this.ServerInfoPanel.ResumeLayout(false); this.ServerInfoPanel.PerformLayout(); - ((System.ComponentModel.ISupportInitialize)(this.CheckBindingSource)).EndInit(); - ((System.ComponentModel.ISupportInitialize)(this.CheckResultBindingSource)).EndInit(); this.ResumeLayout(false); } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/ServerForm.cs --- a/ServerMonitor/Forms/ServerForm.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/ServerForm.cs Sun Feb 10 20:51:26 2019 -0500 @@ -1,4 +1,5 @@ -using System; +using ServerMonitorApp.Properties; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -23,9 +24,9 @@ public Server Server { get; private set; } - private IEnumerable SelectedChecks { get { return CheckGrid.SelectedRows.Cast().Select(r => r.DataBoundItem).Cast(); } } + private IEnumerable SelectedChecks => CheckGrid.SelectedRows.Cast().Select(r => r.DataBoundItem).Cast(); - private Check SelectedCheck { get { return SelectedChecks.FirstOrDefault(); } } + private Check SelectedCheck => SelectedChecks.FirstOrDefault(); public ServerForm(ServerMonitor monitor, Server server, bool isNewServer = false) { @@ -70,8 +71,17 @@ UpdateCheckButtons(); } + public void Show(bool activate) + { + if (!activate) + WindowState = FormWindowState.Minimized; + Show(); + } + private void Monitor_CheckStatusChanged(object sender, CheckStatusChangedEventArgs e) { + if (e.Check.Server != Server) + return; CheckGrid.Refresh(); if (e.CheckResult != null && logResults != null) { @@ -175,7 +185,7 @@ private void DeleteSelectedChecks() { - if (Properties.Settings.Default.ConfirmDeleteCheck) + if (Settings.Default.ConfirmDeleteCheck) { string message = "Delete " + (SelectedChecks.Count() == 1 ? "\"" + SelectedCheck.Name + "\"" : "selected checks") + "?"; using (CheckBoxDialog dialog = new CheckBoxDialog { Message = message }) @@ -183,8 +193,8 @@ DialogResult result = dialog.ShowDialog(); if (dialog.Checked && result == DialogResult.OK) { - Properties.Settings.Default.ConfirmDeleteCheck = false; - Properties.Settings.Default.Save(); + Settings.Default.ConfirmDeleteCheck = false; + Settings.Default.Save(); } if (result != DialogResult.OK) return; @@ -199,10 +209,10 @@ await Task.WhenAll(checks.Select(c => monitor.ExecuteCheckAsync(c))); } - private void ShowLog(Check check) + public void ShowLog(Check check) { + CheckTabControl.SelectedTab = LogTabPage; LogCheckComboBox.SelectedItem = check; - CheckTabControl.SelectedTab = LogTabPage; } private void UpdateCheckButtons() @@ -223,7 +233,7 @@ { foreach (Control control in ServerInfoPanel.Controls.OfType().Where(c => c is TextBox)) control.TextChanged += (sender, e) => UpdateServer(false); - foreach (Control control in Controls.OfType().Where(c => c is ComboBox)) + foreach (Control control in ServerInfoPanel.Controls.OfType().Where(c => c is ComboBox)) control.TextChanged += (sender, e) => UpdateServer(); foreach (CheckBox control in LogTabPage.Controls.OfType()) control.CheckedChanged += FilterChanged; @@ -354,6 +364,21 @@ } } + private void ServerForm_Activated(object sender, EventArgs e) + { + Win32Helpers.StopFlashWindowEx(this); + } + + private void KeyBrowseButton_Click(object sender, EventArgs e) + { + OpenFileDialog dialog = new OpenFileDialog() { Title = "Select private key file" }; + if (dialog.ShowDialog() == DialogResult.OK) + { + KeyTextBox.Text = dialog.FileName; + UpdateServer(); + } + } + private bool MatchesFilter(CheckResult result) { return filteredStatuses.Contains(result.CheckStatus) && (LogCheckComboBox.SelectedIndex == 0 || LogCheckComboBox.SelectedItem == result.Check); diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/ServerSummaryForm.Designer.cs --- a/ServerMonitor/Forms/ServerSummaryForm.Designer.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/ServerSummaryForm.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -28,17 +28,61 @@ /// private void InitializeComponent() { + this.components = new System.ComponentModel.Container(); this.ServerPanel = new System.Windows.Forms.FlowLayoutPanel(); + this.NotifyIcon = new System.Windows.Forms.NotifyIcon(this.components); + this.ServerContextMenu = new System.Windows.Forms.ContextMenuStrip(this.components); + this.DeleteServerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.SettingsButton = new System.Windows.Forms.Button(); this.NewServerButton = new System.Windows.Forms.Button(); + this.ToggleEnableServerMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.ServerContextMenu.SuspendLayout(); this.SuspendLayout(); // // ServerPanel // + this.ServerPanel.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); this.ServerPanel.Location = new System.Drawing.Point(12, 12); this.ServerPanel.Name = "ServerPanel"; - this.ServerPanel.Size = new System.Drawing.Size(560, 308); + this.ServerPanel.Size = new System.Drawing.Size(767, 391); this.ServerPanel.TabIndex = 0; // + // NotifyIcon + // + this.NotifyIcon.Text = "Server Monitor"; + this.NotifyIcon.Visible = true; + this.NotifyIcon.BalloonTipClicked += new System.EventHandler(this.NotifyIcon_BalloonTipClicked); + // + // ServerContextMenu + // + this.ServerContextMenu.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.ToggleEnableServerMenuItem, + this.DeleteServerMenuItem}); + this.ServerContextMenu.Name = "ServerContextMenu"; + this.ServerContextMenu.Size = new System.Drawing.Size(181, 70); + this.ServerContextMenu.Opening += new System.ComponentModel.CancelEventHandler(this.ServerContextMenu_Opening); + this.ServerContextMenu.ItemClicked += new System.Windows.Forms.ToolStripItemClickedEventHandler(this.ServerContextMenu_ItemClicked); + // + // DeleteServerMenuItem + // + this.DeleteServerMenuItem.Name = "DeleteServerMenuItem"; + this.DeleteServerMenuItem.Size = new System.Drawing.Size(180, 22); + this.DeleteServerMenuItem.Text = "Delete server"; + // + // SettingsButton + // + this.SettingsButton.Image = global::ServerMonitorApp.Properties.Resources.settings; + this.SettingsButton.Location = new System.Drawing.Point(264, 409); + this.SettingsButton.Name = "SettingsButton"; + this.SettingsButton.Size = new System.Drawing.Size(92, 29); + this.SettingsButton.TabIndex = 1; + this.SettingsButton.Text = "Settings"; + this.SettingsButton.TextImageRelation = System.Windows.Forms.TextImageRelation.ImageBeforeText; + this.SettingsButton.UseVisualStyleBackColor = true; + this.SettingsButton.Click += new System.EventHandler(this.SettingsButton_Click); + // // NewServerButton // this.NewServerButton.Image = global::ServerMonitorApp.Properties.Resources.add; @@ -51,16 +95,25 @@ this.NewServerButton.UseVisualStyleBackColor = true; this.NewServerButton.Click += new System.EventHandler(this.NewServerButton_Click); // + // ToggleEnableServerMenuItem + // + this.ToggleEnableServerMenuItem.Name = "ToggleEnableServerMenuItem"; + this.ToggleEnableServerMenuItem.Size = new System.Drawing.Size(180, 22); + this.ToggleEnableServerMenuItem.Text = "Disable"; + // // ServerSummaryForm // this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.ClientSize = new System.Drawing.Size(800, 450); + this.Controls.Add(this.SettingsButton); this.Controls.Add(this.NewServerButton); this.Controls.Add(this.ServerPanel); this.Name = "ServerSummaryForm"; this.Text = "Form1"; + this.FormClosing += new System.Windows.Forms.FormClosingEventHandler(this.ServerSummaryForm_FormClosing); this.Load += new System.EventHandler(this.ServerSummaryForm_Load); + this.ServerContextMenu.ResumeLayout(false); this.ResumeLayout(false); } @@ -69,6 +122,11 @@ private System.Windows.Forms.FlowLayoutPanel ServerPanel; private System.Windows.Forms.Button NewServerButton; + private System.Windows.Forms.NotifyIcon NotifyIcon; + private System.Windows.Forms.Button SettingsButton; + private System.Windows.Forms.ContextMenuStrip ServerContextMenu; + private System.Windows.Forms.ToolStripMenuItem DeleteServerMenuItem; + private System.Windows.Forms.ToolStripMenuItem ToggleEnableServerMenuItem; } } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/ServerSummaryForm.cs --- a/ServerMonitor/Forms/ServerSummaryForm.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/ServerSummaryForm.cs Sun Feb 10 20:51:26 2019 -0500 @@ -1,4 +1,5 @@ -using System; +using ServerMonitorApp.Properties; +using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; @@ -19,10 +20,29 @@ InitializeComponent(); } + public void AlertServerForm(Check check) + { + bool existingForm = serverForms.ContainsKey(check.Server); + ServerForm form = ShowServerForm(check.Server, false); + Win32Helpers.FlashWindowEx(form); + if (!existingForm) + { + form.ShowLog(check); + } + } + + public void ShowBalloon(CheckResult result) + { + string title = string.Format("{0}: {1} failed", result.Check.Server.Name, result.Check.Name); + NotifyIcon.Tag = result; + NotifyIcon.ShowBalloonTip(30000, title, result.Message, GetToolTipIcon(result.CheckStatus)); + } + private void ServerSummaryForm_Load(object sender, EventArgs e) { Helpers.FormatImageButton(NewServerButton); - monitor = new ServerMonitor(); + Helpers.FormatImageButton(SettingsButton); + monitor = new ServerMonitor(this); while (true) { try @@ -41,21 +61,12 @@ } } } + NotifyIcon.Icon = new Icon(Icon, 16, 16); + monitor.CheckStatusChanged += Monitor_CheckStatusChanged; RefreshDisplay(); } - private void RefreshDisplay() - { - ServerPanel.Controls.Clear(); - foreach (Server server in monitor.Servers) - { - ServerSummaryControl control = new ServerSummaryControl(server); - control.Click += ServerSummaryControl_Click; - ServerPanel.Controls.Add(control); - } - } - - private void ShowServerForm(Server server) + private ServerForm ShowServerForm(Server server, bool activate = true) { bool isNewServer = false; if (server == null) @@ -66,14 +77,45 @@ } if (serverForms.TryGetValue(server, out ServerForm form)) { - form.Activate(); + if (activate) + form.Activate(); } else { form = new ServerForm(monitor, server, isNewServer); serverForms[server] = form; form.FormClosing += ServerForm_FormClosing; - form.Show(); + form.Show(activate); + } + return form; + } + + private void RefreshDisplay() + { + ServerPanel.Controls.Clear(); + foreach (Server server in monitor.Servers) + { + ServerSummaryControl control = new ServerSummaryControl(server); + control.ContextMenuStrip = ServerContextMenu; + control.Click += ServerSummaryControl_Click; + ServerPanel.Controls.Add(control); + } + } + + private void Monitor_CheckStatusChanged(object sender, CheckStatusChangedEventArgs e) + { + if (e.CheckResult != null) + ServerPanel.Controls.Cast().FirstOrDefault(c => c.Server == e.Check.Server).Refresh(); + } + + private ToolTipIcon GetToolTipIcon(CheckStatus status) + { + switch (status) + { + case CheckStatus.Error: return ToolTipIcon.Error; + case CheckStatus.Warning: return ToolTipIcon.Warning; + case CheckStatus.Information: return ToolTipIcon.Info; + default: return ToolTipIcon.None; } } @@ -86,7 +128,12 @@ { ServerForm form = (ServerForm)sender; form.FormClosing -= ServerForm_FormClosing; + Server server = form.Server; serverForms.Remove(form.Server); + if (server.IsEmpty()) + { + monitor.DeleteServer(server); + } RefreshDisplay(); } @@ -94,5 +141,63 @@ { ShowServerForm(null); } + + private void ServerSummaryForm_FormClosing(object sender, FormClosingEventArgs e) + { + if (e.CloseReason == CloseReason.None || e.CloseReason == CloseReason.UserClosing) + { + Hide(); + e.Cancel = true; + } + } + + private void SettingsButton_Click(object sender, EventArgs e) + { + new SettingsForm().Show(); + } + + private void NotifyIcon_BalloonTipClicked(object sender, EventArgs e) + { + CheckResult result = (CheckResult)(sender as NotifyIcon).Tag; + ServerForm form = ShowServerForm(result.Check.Server); + form.ShowLog(result.Check); + form.WindowState = FormWindowState.Normal; + } + + private void ServerContextMenu_ItemClicked(object sender, ToolStripItemClickedEventArgs e) + { + Server server = getClickedServer((ContextMenuStrip)e.ClickedItem.Owner); + if (e.ClickedItem == DeleteServerMenuItem) + { + ServerContextMenu.Close(); + DialogResult result = MessageBox.Show( + string.Format("The server \"{0}\" and its {1} {2} will be deleted.", server.Name, server.Checks.Count, server.Checks.Count == 1 ? "check" : "checks"), + "Delete server", + MessageBoxButtons.OKCancel, + MessageBoxIcon.Warning ); + if (result == DialogResult.OK) + { + monitor.DeleteServer(server); + RefreshDisplay(); + } + } + else if (e.ClickedItem == ToggleEnableServerMenuItem) + { + bool enable = ToggleEnableServerMenuItem.Text == "Enable"; + server.Enabled = enable; + RefreshDisplay(); + } + } + + private void ServerContextMenu_Opening(object sender, CancelEventArgs e) + { + Server server = getClickedServer((ContextMenuStrip)sender); + ToggleEnableServerMenuItem.Text = server.Enabled ? "Disable" : "Enable"; + } + + private Server getClickedServer(ContextMenuStrip menu) + { + return ((ServerSummaryControl)menu.SourceControl).Server; + } } } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/ServerSummaryForm.resx --- a/ServerMonitor/Forms/ServerSummaryForm.resx Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Forms/ServerSummaryForm.resx Sun Feb 10 20:51:26 2019 -0500 @@ -117,4 +117,10 @@ System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + 17, 17 + + + 125, 17 + \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/SettingsForm.Designer.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerMonitor/Forms/SettingsForm.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -0,0 +1,225 @@ +namespace ServerMonitorApp +{ + partial class SettingsForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SeverityOptionsGroupBox = new System.Windows.Forms.GroupBox(); + this.ErrorComboBox = new System.Windows.Forms.ComboBox(); + this.WarningComboBox = new System.Windows.Forms.ComboBox(); + this.InformationComboBox = new System.Windows.Forms.ComboBox(); + this.InformationLabel = new System.Windows.Forms.Label(); + this.InformationIcon = new System.Windows.Forms.PictureBox(); + this.WarningLabel = new System.Windows.Forms.Label(); + this.WarningIcon = new System.Windows.Forms.PictureBox(); + this.ErrorLabel = new System.Windows.Forms.Label(); + this.ErrorIcon = new System.Windows.Forms.PictureBox(); + this.label1 = new System.Windows.Forms.Label(); + this.OkButton = new System.Windows.Forms.Button(); + this.CancelSettingsButton = new System.Windows.Forms.Button(); + this.SeverityOptionsGroupBox.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.InformationIcon)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.WarningIcon)).BeginInit(); + ((System.ComponentModel.ISupportInitialize)(this.ErrorIcon)).BeginInit(); + this.SuspendLayout(); + // + // SeverityOptionsGroupBox + // + this.SeverityOptionsGroupBox.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.SeverityOptionsGroupBox.Controls.Add(this.ErrorComboBox); + this.SeverityOptionsGroupBox.Controls.Add(this.WarningComboBox); + this.SeverityOptionsGroupBox.Controls.Add(this.InformationComboBox); + this.SeverityOptionsGroupBox.Controls.Add(this.InformationLabel); + this.SeverityOptionsGroupBox.Controls.Add(this.InformationIcon); + this.SeverityOptionsGroupBox.Controls.Add(this.WarningLabel); + this.SeverityOptionsGroupBox.Controls.Add(this.WarningIcon); + this.SeverityOptionsGroupBox.Controls.Add(this.ErrorLabel); + this.SeverityOptionsGroupBox.Controls.Add(this.ErrorIcon); + this.SeverityOptionsGroupBox.Location = new System.Drawing.Point(12, 57); + this.SeverityOptionsGroupBox.Name = "SeverityOptionsGroupBox"; + this.SeverityOptionsGroupBox.Size = new System.Drawing.Size(337, 104); + this.SeverityOptionsGroupBox.TabIndex = 0; + this.SeverityOptionsGroupBox.TabStop = false; + this.SeverityOptionsGroupBox.Text = "Severity settings"; + // + // ErrorComboBox + // + this.ErrorComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.ErrorComboBox.FormattingEnabled = true; + this.ErrorComboBox.Location = new System.Drawing.Point(125, 17); + this.ErrorComboBox.Name = "ErrorComboBox"; + this.ErrorComboBox.Size = new System.Drawing.Size(121, 21); + this.ErrorComboBox.TabIndex = 8; + // + // WarningComboBox + // + this.WarningComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.WarningComboBox.FormattingEnabled = true; + this.WarningComboBox.Location = new System.Drawing.Point(125, 44); + this.WarningComboBox.Name = "WarningComboBox"; + this.WarningComboBox.Size = new System.Drawing.Size(121, 21); + this.WarningComboBox.TabIndex = 7; + // + // InformationComboBox + // + this.InformationComboBox.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.InformationComboBox.FormattingEnabled = true; + this.InformationComboBox.Location = new System.Drawing.Point(125, 71); + this.InformationComboBox.Name = "InformationComboBox"; + this.InformationComboBox.Size = new System.Drawing.Size(121, 21); + this.InformationComboBox.TabIndex = 6; + // + // InformationLabel + // + this.InformationLabel.AutoSize = true; + this.InformationLabel.Location = new System.Drawing.Point(25, 74); + this.InformationLabel.Name = "InformationLabel"; + this.InformationLabel.Size = new System.Drawing.Size(94, 13); + this.InformationLabel.TabIndex = 5; + this.InformationLabel.Text = "Information action:"; + // + // InformationIcon + // + this.InformationIcon.Image = global::ServerMonitorApp.Properties.Resources.info; + this.InformationIcon.Location = new System.Drawing.Point(6, 73); + this.InformationIcon.Name = "InformationIcon"; + this.InformationIcon.Size = new System.Drawing.Size(16, 16); + this.InformationIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.InformationIcon.TabIndex = 4; + this.InformationIcon.TabStop = false; + // + // WarningLabel + // + this.WarningLabel.AutoSize = true; + this.WarningLabel.Location = new System.Drawing.Point(25, 47); + this.WarningLabel.Name = "WarningLabel"; + this.WarningLabel.Size = new System.Drawing.Size(82, 13); + this.WarningLabel.TabIndex = 3; + this.WarningLabel.Text = "Warning action:"; + // + // WarningIcon + // + this.WarningIcon.Image = global::ServerMonitorApp.Properties.Resources.warning; + this.WarningIcon.Location = new System.Drawing.Point(6, 46); + this.WarningIcon.Name = "WarningIcon"; + this.WarningIcon.Size = new System.Drawing.Size(16, 16); + this.WarningIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.WarningIcon.TabIndex = 2; + this.WarningIcon.TabStop = false; + // + // ErrorLabel + // + this.ErrorLabel.AutoSize = true; + this.ErrorLabel.Location = new System.Drawing.Point(25, 20); + this.ErrorLabel.Name = "ErrorLabel"; + this.ErrorLabel.Size = new System.Drawing.Size(64, 13); + this.ErrorLabel.TabIndex = 1; + this.ErrorLabel.Text = "Error action:"; + // + // ErrorIcon + // + this.ErrorIcon.Image = global::ServerMonitorApp.Properties.Resources.error; + this.ErrorIcon.Location = new System.Drawing.Point(6, 19); + this.ErrorIcon.Name = "ErrorIcon"; + this.ErrorIcon.Size = new System.Drawing.Size(16, 16); + this.ErrorIcon.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom; + this.ErrorIcon.TabIndex = 0; + this.ErrorIcon.TabStop = false; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(9, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(50, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Options"; + // + // OkButton + // + this.OkButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.OkButton.Location = new System.Drawing.Point(193, 170); + this.OkButton.Name = "OkButton"; + this.OkButton.Size = new System.Drawing.Size(75, 23); + this.OkButton.TabIndex = 2; + this.OkButton.Text = "OK"; + this.OkButton.UseVisualStyleBackColor = true; + this.OkButton.Click += new System.EventHandler(this.OkButton_Click); + // + // CancelSettingsButton + // + this.CancelSettingsButton.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right))); + this.CancelSettingsButton.Location = new System.Drawing.Point(274, 170); + this.CancelSettingsButton.Name = "CancelSettingsButton"; + this.CancelSettingsButton.Size = new System.Drawing.Size(75, 23); + this.CancelSettingsButton.TabIndex = 3; + this.CancelSettingsButton.Text = "Cancel"; + this.CancelSettingsButton.UseVisualStyleBackColor = true; + this.CancelSettingsButton.Click += new System.EventHandler(this.CancelSettingsButton_Click); + // + // SettingsForm + // + this.AcceptButton = this.OkButton; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(361, 205); + this.Controls.Add(this.CancelSettingsButton); + this.Controls.Add(this.OkButton); + this.Controls.Add(this.label1); + this.Controls.Add(this.SeverityOptionsGroupBox); + this.Name = "SettingsForm"; + this.Text = "Options"; + this.Load += new System.EventHandler(this.SettingsForm_Load); + this.SeverityOptionsGroupBox.ResumeLayout(false); + this.SeverityOptionsGroupBox.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.InformationIcon)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.WarningIcon)).EndInit(); + ((System.ComponentModel.ISupportInitialize)(this.ErrorIcon)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.GroupBox SeverityOptionsGroupBox; + private System.Windows.Forms.PictureBox ErrorIcon; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.Label InformationLabel; + private System.Windows.Forms.PictureBox InformationIcon; + private System.Windows.Forms.Label WarningLabel; + private System.Windows.Forms.PictureBox WarningIcon; + private System.Windows.Forms.Label ErrorLabel; + private System.Windows.Forms.ComboBox ErrorComboBox; + private System.Windows.Forms.ComboBox WarningComboBox; + private System.Windows.Forms.ComboBox InformationComboBox; + private System.Windows.Forms.Button OkButton; + private System.Windows.Forms.Button CancelSettingsButton; + } +} \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/SettingsForm.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerMonitor/Forms/SettingsForm.cs Sun Feb 10 20:51:26 2019 -0500 @@ -0,0 +1,53 @@ +using ServerMonitorApp.Properties; +using System; +using System.Collections.Generic; +using System.ComponentModel; +using System.Data; +using System.Drawing; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ServerMonitorApp +{ + public partial class SettingsForm : Form + { + public SettingsForm() + { + InitializeComponent(); + } + + private void SettingsForm_Load(object sender, EventArgs e) + { + foreach (ComboBox comboBox in new object[] { ErrorComboBox, WarningComboBox, InformationComboBox }) + { + comboBox.DataSource = Enum.GetValues(typeof(FailAction)); + comboBox.Format += FailActionComboBox_Format; + } + ErrorComboBox.SelectedItem = Settings.Default.ErrorAction; + WarningComboBox.SelectedItem = Settings.Default.WarningAction; + InformationComboBox.SelectedItem = Settings.Default.InformationAction; + } + + private void FailActionComboBox_Format(object sender, ListControlConvertEventArgs e) + { + e.Value = e.Value.ToString().Substring(0, 1) + Regex.Replace(e.Value.ToString(), "(\\B[A-Z])", " $1").ToLower().Substring(1); + } + + private void OkButton_Click(object sender, EventArgs e) + { + Settings.Default.ErrorAction = (FailAction)ErrorComboBox.SelectedItem; + Settings.Default.WarningAction = (FailAction)WarningComboBox.SelectedItem; + Settings.Default.InformationAction = (FailAction)InformationComboBox.SelectedItem; + Settings.Default.Save(); + Close(); + } + + private void CancelSettingsButton_Click(object sender, EventArgs e) + { + Close(); + } + } +} diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Forms/SettingsForm.resx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerMonitor/Forms/SettingsForm.resx Sun Feb 10 20:51:26 2019 -0500 @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Helpers.cs --- a/ServerMonitor/Helpers.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Helpers.cs Sun Feb 10 20:51:26 2019 -0500 @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Drawing; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Windows.Forms; @@ -50,6 +51,7 @@ case CheckStatus.Information: return Resources.info; case CheckStatus.Success: return Resources.pass; case CheckStatus.Running: return Resources.run; + case CheckStatus.Disabled: return Resources.disable; default: return null; } } @@ -57,5 +59,40 @@ public static bool In(this Enum value, params Enum[] values) { return values.Contains(value); } + + // https://stackoverflow.com/a/8345173 + /// + /// Indicates whether any network connection is available. + /// Filter connections below a specified speed, as well as virtual network cards. + /// + /// + /// true if a network connection is available; otherwise, false. + /// + public static bool IsNetworkAvailable() + { + if (!NetworkInterface.GetIsNetworkAvailable()) + return false; + + foreach (NetworkInterface ni in NetworkInterface.GetAllNetworkInterfaces()) + { + // discard because of standard reasons + if ((ni.OperationalStatus != OperationalStatus.Up) || + (ni.NetworkInterfaceType == NetworkInterfaceType.Loopback) || + (ni.NetworkInterfaceType == NetworkInterfaceType.Tunnel)) + continue; + + // discard virtual cards (virtual box, virtual pc, etc.) + if ((ni.Description.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0) || + (ni.Name.IndexOf("virtual", StringComparison.OrdinalIgnoreCase) >= 0)) + continue; + + // discard "Microsoft Loopback Adapter", it will not show as NetworkInterfaceType.Loopback but as Ethernet Card. + if (ni.Description.Equals("Microsoft Loopback Adapter", StringComparison.OrdinalIgnoreCase)) + continue; + + return true; + } + return false; + } } } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/CheckResult.cs --- a/ServerMonitor/Objects/CheckResult.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/CheckResult.cs Sun Feb 10 20:51:26 2019 -0500 @@ -18,6 +18,24 @@ public DateTime EndTime { get; set; } + public bool Failed => CheckStatus != CheckStatus.Success; + + public FailAction FailAction + { + get + { + switch (CheckStatus) + { + case CheckStatus.Error: return Settings.Default.ErrorAction; + case CheckStatus.Warning: return Settings.Default.WarningAction; + case CheckStatus.Information: return Settings.Default.InformationAction; + default: return FailAction.None; + } + } + } + + public bool FlashTaskbar => FailAction == FailAction.FlashTaskbar; + public CheckResult(Check check, CheckStatus status, string message) { Check = check; diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/Checks/Check.cs --- a/ServerMonitor/Objects/Checks/Check.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/Checks/Check.cs Sun Feb 10 20:51:26 2019 -0500 @@ -59,6 +59,8 @@ public CheckStatus Status { get; set; } + public CheckStatus LastRunStatus { get; set; } + public CheckStatus FailStatus { get; set; } [XmlIgnore] @@ -90,7 +92,9 @@ public async Task ExecuteAsync(CancellationToken token = default(CancellationToken), bool update = true) { - //TODO check cancellation token before proceeding + if (token.IsCancellationRequested) + return null; + CheckResult result; DateTime startTime = DateTime.Now; try @@ -122,6 +126,7 @@ if (update) { Status = result.CheckStatus; + LastRunStatus = result.CheckStatus; LastMessage = result.Message; LastRunTime = result.EndTime; } @@ -222,7 +227,7 @@ { if (result == null) continue; - if (result.CheckStatus != CheckStatus.Success) + if (result.Failed) failed = true; message.AppendLine(result.Message); } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/Checks/DiskSpaceCheck.cs --- a/ServerMonitor/Objects/Checks/DiskSpaceCheck.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/Checks/DiskSpaceCheck.cs Sun Feb 10 20:51:26 2019 -0500 @@ -10,7 +10,7 @@ [DisplayName("Disk space check"), Description("Check the remaining free disk space"), DisplayWeight(11)] public class DiskSpaceCheck : SshCheck { - public override string Command { get => string.Format(base.Command, Device); } + public override string Command => string.Format(base.Command, Device); public string Device { get; set; } @@ -29,7 +29,7 @@ protected override List ProcessCommandResult(string output, int exitCode) { List results = base.ProcessCommandResult(output, exitCode); - if (results.Any(r => r.CheckStatus != CheckStatus.Success)) + if (results.Any(r => r.Failed)) return results; List lines = output.Split('\n').ToList(); diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/Checks/FileCheck.cs --- a/ServerMonitor/Objects/Checks/FileCheck.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/Checks/FileCheck.cs Sun Feb 10 20:51:26 2019 -0500 @@ -11,7 +11,7 @@ [DisplayName("File check"), Description("Check file size or modified time"), DisplayWeight(12)] public class FileCheck : SshCheck { - public override string Command { get => string.Format(base.Command, Regex.Replace(File, "^~", "$HOME")); } + public override string Command => string.Format(base.Command, Regex.Replace(File, "^~", "$HOME")); public string File { get; set; } @@ -19,12 +19,12 @@ public bool FileSizeLessThan { get; set; } - public double FileSize { get; set; } + public int FileSize { get; set; } public double FileSizeInSelectedUnits { - get { return FileSize / Math.Pow(1024, (double)FileSizeUnits); } - set { FileSize = value * Math.Pow(1024, (double)FileSizeUnits); } + get => Math.Round(ConvertBytesToSelectedUnits(FileSize), 1); + set => FileSize = ConvertSelectedUnitsToBytes(value); } public SizeUnits FileSizeUnits { get; set; } @@ -48,7 +48,7 @@ protected override List ProcessCommandResult(string output, int exitCode) { List results = base.ProcessCommandResult(output, exitCode); - if (results.Any(r => r.CheckStatus != CheckStatus.Success)) + if (results.Any(r => r.Failed)) return results; if (output.Split('\n').Length > 1) @@ -62,7 +62,7 @@ { if (int.TryParse(tokens[4], out int bytes)) { - string message = string.Format("File size is {0} {1}", bytes / Math.Pow(1024, (double)FileSizeUnits), FileSizeUnits); + string message = string.Format("File size is {0} {1}", Math.Round(ConvertBytesToSelectedUnits(bytes), 1), FileSizeUnits); if ((bytes < FileSize && FileSizeLessThan) || (bytes > FileSize && !FileSizeLessThan)) results.Add(Pass(message)); else @@ -110,5 +110,15 @@ message += "Date modified must be greater than 0." + Environment.NewLine; return message; } + + private double ConvertBytesToSelectedUnits(int sizeInBytes) + { + return sizeInBytes / Math.Pow(1024, (double)FileSizeUnits); + } + + private int ConvertSelectedUnitsToBytes(double sizeInSelectedUnits) + { + return (int)(sizeInSelectedUnits * Math.Pow(1024, (int)FileSizeUnits)); + } } } \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/Checks/SshCheck.cs --- a/ServerMonitor/Objects/Checks/SshCheck.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/Checks/SshCheck.cs Sun Feb 10 20:51:26 2019 -0500 @@ -74,7 +74,7 @@ if (CheckExitCode) { CheckResult result = GetIntResult(ExitCode, exitCode, "Exit code"); - if (result.CheckStatus != CheckStatus.Success) + if (result.Failed) result.Message += ". Command output: " + output; results.Add(result); } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/Schedule.cs --- a/ServerMonitor/Objects/Schedule.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/Schedule.cs Sun Feb 10 20:51:26 2019 -0500 @@ -41,7 +41,6 @@ // If the last run time was more than a day ago, fast-forward to reduce the number of loops if (nextTime < minStartTime.AddHours(-24)) nextTime = minStartTime.Date.Add(StartTime).AddHours(-24); - //TODO handle start time and end time while (nextTime < minStartTime) { switch (Units) diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/Server.cs --- a/ServerMonitor/Objects/Server.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/Server.cs Sun Feb 10 20:51:26 2019 -0500 @@ -19,9 +19,11 @@ private LoginType _loginType; private string _keyFile; private SshClient _sshClient; + private bool _enabled = true; private byte[] passwordHash; public event EventHandler CheckModified; + public event EventHandler EnabledChanged; public readonly BindingList Checks = new BindingList(); @@ -73,7 +75,17 @@ } } - public bool Enabled { get; set; } = true; + public bool Enabled + { + get { return _enabled; } + set { _enabled = value; EnabledChanged?.Invoke(this, new EventArgs()); } + } + + public CheckStatus Status => !Enabled ? CheckStatus.Disabled : Checks + .Where(c => c.Enabled) + .Select(c => c.LastRunStatus) + .DefaultIfEmpty(CheckStatus.Success) + .Max(); public SshClient SshClient { @@ -85,7 +97,7 @@ if (LoginType == LoginType.Password) auth = new PasswordAuthenticationMethod(Username, Password); else - new PrivateKeyAuthenticationMethod(Username, new PrivateKeyFile(KeyFile)); + auth = new PrivateKeyAuthenticationMethod(Username, new PrivateKeyFile(KeyFile)); ConnectionInfo info = new ConnectionInfo(Host, Port, Username, auth); _sshClient = new SshClient(info); } @@ -137,6 +149,13 @@ CheckModified?.Invoke(check, new EventArgs()); } + public bool IsEmpty() + { + return Name.IsNullOrEmpty() + && Host.IsNullOrEmpty() + && Checks.Count == 0; + } + private void InvalidateSshConnection() { _sshClient?.Dispose(); diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Objects/ServerMonitor.cs --- a/ServerMonitor/Objects/ServerMonitor.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Objects/ServerMonitor.cs Sun Feb 10 20:51:26 2019 -0500 @@ -1,11 +1,14 @@ -using System; +using ServerMonitorApp.Properties; +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; +using System.Net.NetworkInformation; using System.Text; using System.Threading; using System.Threading.Tasks; +using System.Windows.Forms; using System.Xml.Serialization; namespace ServerMonitorApp @@ -15,20 +18,24 @@ private readonly string configFileDir; private readonly Logger logger; private readonly Dictionary tokens = new Dictionary(); - private bool running; + private readonly List pausedChecks = new List(); + private bool running, networkAvailable; private Dictionary, int> tasks; + private ServerSummaryForm mainForm; + //private List> tasks; public event EventHandler CheckStatusChanged; public List Servers { get; private set; } = new List(); - public IEnumerable Checks { get { return Servers.SelectMany(s => s.Checks); } } + public IEnumerable Checks => Servers.SelectMany(s => s.Checks); public string ConfigFile { get; private set; } - public ServerMonitor() + public ServerMonitor(ServerSummaryForm mainForm) { + this.mainForm = mainForm; configFileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData), "ServerMonitor"); ConfigFile = Path.Combine(configFileDir, "servers.xml"); logger = new Logger(Path.Combine(configFileDir, "monitor.log")); @@ -37,6 +44,13 @@ public void AddServer(Server server) { Servers.Add(server); + SaveServers(); + } + + public void DeleteServer(Server server) + { + Servers.Remove(server); + SaveServers(); } public void LoadServers() @@ -56,8 +70,11 @@ foreach (Check check in server.Checks) { check.Server = server; + if (check.Status == CheckStatus.Running) + check.Status = check.LastRunStatus; } server.CheckModified += Server_CheckModified; + server.EnabledChanged += Server_EnabledChanged; } } // If the file doesn't exist, no special handling is needed. It will be created later. @@ -72,6 +89,7 @@ { reader?.Close(); } + NetworkChange.NetworkAddressChanged += NetworkChange_NetworkAddressChanged; Run(); } @@ -109,6 +127,15 @@ if (running) return; running = true; + networkAvailable = Helpers.IsNetworkAvailable(); + if (networkAvailable) + { + foreach (int id in pausedChecks) + { + await ExecuteCheckAsync(Checks.FirstOrDefault(c => c.Id == id)); + } + pausedChecks.Clear(); + } //TODO subscribe to power events. Find any check's NextExecutionTime is in the past. Cancel waiting task and run immediately (or after short delay). //tasks = Checks.Select(c => ScheduleExecuteCheckAsync(c)).ToList(); tasks = Checks.ToDictionary(c => ScheduleExecuteCheckAsync(c), c => c.Id); @@ -137,8 +164,17 @@ OnCheckStatusChanged(check); CheckResult result = await check.ExecuteAsync(token); OnCheckStatusChanged(check, result); + HandleResultAsync(result); + return result; + } + + private void HandleResultAsync(CheckResult result) + { logger.Log(result); - return result; + if (result.FailAction == FailAction.FlashTaskbar) + mainForm.AlertServerForm(result.Check); + if (result.FailAction.In(FailAction.FlashTaskbar, FailAction.NotificationBalloon)) + mainForm.ShowBalloon(result); } public IList GetLog(Server server) @@ -166,9 +202,7 @@ else { // Check was modified or deleted, so remove any waiting tasks - tasks.Remove(task); - if (tokens.TryGetValue(check.Id, out CancellationTokenSource cts)) - cts.Cancel(); + CancelCheck(check); if (check.Server != null) { // If the check was not deleted, schedule the new check. @@ -183,9 +217,34 @@ Run(); } + private void Server_EnabledChanged(object sender, EventArgs e) + { + Server server = (Server)sender; + if (server.Enabled) + { + Run(); + } + else + { + foreach (Check check in server.Checks) + { + CancelCheck(check); + } + } + } + + private void CancelCheck(Check check) + { + Task task = tasks.FirstOrDefault(kvp => kvp.Value == check.Id).Key; + tasks.Remove(task); + pausedChecks.RemoveAll(id => id == check.Id); + if (tokens.TryGetValue(check.Id, out CancellationTokenSource cts)) + cts.Cancel(); + } + private async Task ScheduleExecuteCheckAsync(Check check) { - if (!check.Enabled) + if (!check.Enabled || !check.Server.Enabled) return await Task.FromResult(new CheckResult(check, CheckStatus.Disabled, null)); CancellationTokenSource cts = new CancellationTokenSource(); @@ -193,7 +252,21 @@ check.NextRunTime = check.Schedule.GetNextTime(check.LastScheduledRunTime); await Task.Delay(check.NextRunTime - DateTime.Now, cts.Token); check.LastScheduledRunTime = check.NextRunTime; - return await ExecuteCheckAsync(check, cts.Token); + if (networkAvailable) + return await ExecuteCheckAsync(check, cts.Token); + else + { + if (!pausedChecks.Contains(check.Id)) + pausedChecks.Add(check.Id); + return await Task.FromResult(new CheckResult(check, CheckStatus.Disabled, null)); + } + } + + private void NetworkChange_NetworkAddressChanged(object sender, EventArgs e) + { + networkAvailable = Helpers.IsNetworkAvailable(); + if (networkAvailable) + mainForm.Invoke((MethodInvoker)(() => Run())); } private void GenerateIds() @@ -208,15 +281,16 @@ } } - //TODO if a check is deleted, there might be old results in the log file that share an ID with a new one if (Checks.Any()) { - int id = Checks.Max(c => c.Id); + int id = Math.Max(Settings.Default.MaxCheckId, Checks.Max(c => c.Id)); foreach (Check check in Checks) { if (check.Id == 0) check.Id = ++id; } + Settings.Default.MaxCheckId = id; + Settings.Default.Save(); } } @@ -237,6 +311,7 @@ Check = check; CheckResult = result; } + } - } + public enum FailAction { FlashTaskbar = 0, NotificationBalloon = 1, None = 10 } } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Properties/Resources.Designer.cs --- a/ServerMonitor/Properties/Resources.Designer.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Properties/Resources.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -83,6 +83,16 @@ /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// + internal static System.Drawing.Bitmap disable { + get { + object obj = ResourceManager.GetObject("disable", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap edit { get { object obj = ResourceManager.GetObject("edit", resourceCulture); @@ -163,6 +173,16 @@ /// /// Looks up a localized resource of type System.Drawing.Bitmap. /// + internal static System.Drawing.Bitmap settings { + get { + object obj = ResourceManager.GetObject("settings", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// internal static System.Drawing.Bitmap warning { get { object obj = ResourceManager.GetObject("warning", resourceCulture); diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Properties/Resources.resx --- a/ServerMonitor/Properties/Resources.resx Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Properties/Resources.resx Sun Feb 10 20:51:26 2019 -0500 @@ -124,6 +124,9 @@ ..\Resources\delete.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\disable.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\edit.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a @@ -148,6 +151,9 @@ ..\Resources\server.png;System.Drawing.Bitmap, System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + ..\Resources\settings.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + ..\Resources\warning.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Properties/Settings.Designer.cs --- a/ServerMonitor/Properties/Settings.Designer.cs Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Properties/Settings.Designer.cs Sun Feb 10 20:51:26 2019 -0500 @@ -12,7 +12,7 @@ [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); @@ -34,5 +34,53 @@ this["ConfirmDeleteCheck"] = value; } } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("FlashTaskbar")] + public global::ServerMonitorApp.FailAction ErrorAction { + get { + return ((global::ServerMonitorApp.FailAction)(this["ErrorAction"])); + } + set { + this["ErrorAction"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("NotificationBalloon")] + public global::ServerMonitorApp.FailAction WarningAction { + get { + return ((global::ServerMonitorApp.FailAction)(this["WarningAction"])); + } + set { + this["WarningAction"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("NotificationBalloon")] + public global::ServerMonitorApp.FailAction InformationAction { + get { + return ((global::ServerMonitorApp.FailAction)(this["InformationAction"])); + } + set { + this["InformationAction"] = value; + } + } + + [global::System.Configuration.UserScopedSettingAttribute()] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Configuration.DefaultSettingValueAttribute("0")] + public int MaxCheckId { + get { + return ((int)(this["MaxCheckId"])); + } + set { + this["MaxCheckId"] = value; + } + } } } diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Properties/Settings.settings --- a/ServerMonitor/Properties/Settings.settings Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/Properties/Settings.settings Sun Feb 10 20:51:26 2019 -0500 @@ -1,9 +1,21 @@  - + True + + FlashTaskbar + + + NotificationBalloon + + + NotificationBalloon + + + 0 + \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Resources/disable.png Binary file ServerMonitor/Resources/disable.png has changed diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Resources/error.png Binary file ServerMonitor/Resources/error.png has changed diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Resources/info.png Binary file ServerMonitor/Resources/info.png has changed diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Resources/pass.png Binary file ServerMonitor/Resources/pass.png has changed diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Resources/settings.png Binary file ServerMonitor/Resources/settings.png has changed diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Resources/warning.png Binary file ServerMonitor/Resources/warning.png has changed diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/ServerMonitor.csproj --- a/ServerMonitor/ServerMonitor.csproj Fri Jan 11 22:34:18 2019 -0500 +++ b/ServerMonitor/ServerMonitor.csproj Sun Feb 10 20:51:26 2019 -0500 @@ -95,6 +95,12 @@ Component + + Form + + + SettingsForm.cs + @@ -146,6 +152,12 @@ ServerSummaryControl.cs + + True + True + Resources.resx + + CheckControl.cs @@ -179,16 +191,14 @@ ServerSummaryForm.cs + + SettingsForm.cs + ResXFileCodeGenerator + Designer Resources.Designer.cs - Designer - - True - Resources.resx - True - @@ -243,6 +253,11 @@ - + + + + + + \ No newline at end of file diff -r 96f0b028176d -r 3142e52cbe69 ServerMonitor/Win32Helpers.cs --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ServerMonitor/Win32Helpers.cs Sun Feb 10 20:51:26 2019 -0500 @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.InteropServices; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Forms; + +namespace ServerMonitorApp +{ + class Win32Helpers + { + [DllImport("user32.dll")] + [return: MarshalAs(UnmanagedType.Bool)] + static extern bool FlashWindowEx(ref FLASHWINFO pwfi); + + [StructLayout(LayoutKind.Sequential)] + public struct FLASHWINFO + { + public UInt32 cbSize; + public IntPtr hwnd; + public UInt32 dwFlags; + public UInt32 uCount; + public UInt32 dwTimeout; + } + + public enum FlashWindowFlags : uint + { + /// + /// Stop flashing. The system restores the window to its original state. + /// + FLASHW_STOP = 0, + + /// + /// Flash the window caption + /// + FLASHW_CAPTION = 1, + + /// + /// Flash the taskbar button. + /// + FLASHW_TRAY = 2, + + /// + /// Flash both the window caption and taskbar button. + /// This is equivalent to setting the FLASHW_CAPTION | FLASHW_TRAY flags. + /// + FLASHW_ALL = 3, + + /// + /// Flash continuously, until the FLASHW_STOP flag is set. + /// + FLASHW_TIMER = 4, + + /// + /// Flash continuously until the window comes to the foreground. + /// + FLASHW_TIMERNOFG = 12 + } + + public static bool FlashWindowEx(Form form) + { + IntPtr hWnd = form.Handle; + FLASHWINFO fInfo = new FLASHWINFO(); + + fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo)); + fInfo.hwnd = hWnd; + fInfo.dwFlags = (uint)FlashWindowFlags.FLASHW_TRAY; + fInfo.uCount = 10; + fInfo.dwTimeout = 0; + + return FlashWindowEx(ref fInfo); + } + + public static bool StopFlashWindowEx(Form form) + { + IntPtr hWnd = form.Handle; + FLASHWINFO fInfo = new FLASHWINFO(); + + fInfo.cbSize = Convert.ToUInt32(Marshal.SizeOf(fInfo)); + fInfo.hwnd = hWnd; + fInfo.dwFlags = (uint)FlashWindowFlags.FLASHW_STOP; + fInfo.dwTimeout = 0; + + return FlashWindowEx(ref fInfo); + } + } +}