Files
TeslaSuite/Console/TeslaConsole/AppControlGrid.cs
T
CydandClaude Opus 4.8 548550b312 Initial commit: TeslaSuite monorepo (TeslaConsole + TeslaLauncher)
Co-locate the two cockpit-pod projects into a single repository:

- Console/  : TeslaConsole, the net48 WinForms operator console (decompiled
              reconstruction) plus its differential + catalog test suite.
- Launcher/ : TeslaLauncher, the net6 pod-side Service + Agent rewrite.

Adds a combined TeslaSuite.sln, root README documenting the shared wire
contract (and its current duplication, the main follow-up), and a root
.gitignore. Histories were not preserved per request; this is a fresh start
from the current working state of both projects.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-29 14:43:28 -05:00

474 lines
15 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using Tesla.Net;
using TeslaConsole.Properties;
namespace TeslaConsole;
public class AppControlGrid : UserControl
{
private class ApplicationInstanceGroup
{
public Guid LaunchKey { get; set; }
public string AppDisplayName { get; set; }
public List<Guid> RunningPods { get; private set; }
public List<Guid> StoppedPods { get; private set; }
public string RunningKey => "running:" + LaunchKey;
public string StoppedKey => "stopped:" + LaunchKey;
public ApplicationInstanceGroup(LaunchPair launchPair)
{
LaunchKey = launchPair.LaunchKey;
AppDisplayName = launchPair.DisplayName;
RunningPods = new List<Guid>();
StoppedPods = new List<Guid>();
}
public void AddInstance(PodAppInstance instance)
{
if (instance.IsRunning)
{
RunningPods.Add(instance.PodId);
}
else
{
StoppedPods.Add(instance.PodId);
}
}
public void StartPod(Guid podId)
{
if (StoppedPods.Contains(podId))
{
StoppedPods.Remove(podId);
if (!RunningPods.Contains(podId))
{
RunningPods.Add(podId);
}
}
}
public void StartAllPods()
{
List<Guid> list = new List<Guid>(StoppedPods);
foreach (Guid item in list)
{
StartPod(item);
}
}
public void StopPod(Guid podId)
{
if (RunningPods.Contains(podId))
{
RunningPods.Remove(podId);
if (!StoppedPods.Contains(podId))
{
StoppedPods.Add(podId);
}
}
}
public void StopAllPods()
{
List<Guid> list = new List<Guid>(RunningPods);
foreach (Guid item in list)
{
StopPod(item);
}
}
public override bool Equals(object obj)
{
if (obj is ApplicationInstanceGroup)
{
return LaunchKey == ((ApplicationInstanceGroup)obj).LaunchKey;
}
return base.Equals(obj);
}
public override int GetHashCode()
{
return LaunchKey.GetHashCode();
}
}
private Dictionary<Guid, ApplicationInstanceGroup> mAppGroups = new Dictionary<Guid, ApplicationInstanceGroup>();
private IContainer components;
private NoSelectDataGridView grdApps;
private DataGridViewLinkColumn colAction;
private DataGridViewTextBoxColumn colStatus;
private DataGridViewTextBoxColumn colName;
private DataGridViewImageColumn colError;
public bool ShowCounts { get; set; }
public event EventHandler<AppEventArgs> LaunchApp;
public event EventHandler<AppEventArgs> KillApp;
public AppControlGrid()
{
InitializeComponent();
}
private void grdApps_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex < 0 || e.RowIndex >= grdApps.Rows.Count)
{
return;
}
DataGridViewRow dataGridViewRow = grdApps.Rows[e.RowIndex];
string text = (string)dataGridViewRow.Tag;
ApplicationInstanceGroup applicationInstanceGroup = mAppGroups[new Guid(text.Split(':')[1])];
if (!(dataGridViewRow.Cells[e.ColumnIndex] is DataGridViewLinkCell dataGridViewLinkCell))
{
return;
}
foreach (DataGridViewRow item in (IEnumerable)grdApps.Rows)
{
item.Cells[3].Value = Resources.Blank;
((List<string>)item.Cells[3].Tag).Clear();
}
Rectangle cellDisplayRectangle = grdApps.GetCellDisplayRectangle(0, e.RowIndex, cutOverflow: false);
PictureBox pictureBox = new PictureBox();
pictureBox.Name = text;
pictureBox.Image = Resources.square_throbber;
pictureBox.SizeMode = PictureBoxSizeMode.CenterImage;
pictureBox.Location = cellDisplayRectangle.Location;
pictureBox.Size = cellDisplayRectangle.Size;
pictureBox.Tag = e.RowIndex;
grdApps.Controls.Add(pictureBox);
pictureBox.BringToFront();
if ((string)dataGridViewLinkCell.Value == "Start")
{
if (this.LaunchApp != null)
{
this.LaunchApp(this, new AppEventArgs(applicationInstanceGroup.LaunchKey, applicationInstanceGroup.StoppedPods));
}
}
else if ((string)dataGridViewLinkCell.Value == "Stop" && this.KillApp != null)
{
this.KillApp(this, new AppEventArgs(applicationInstanceGroup.LaunchKey, applicationInstanceGroup.RunningPods));
}
}
private void grdApps_Scroll(object sender, ScrollEventArgs e)
{
foreach (Control control in grdApps.Controls)
{
if (control is PictureBox)
{
Rectangle cellDisplayRectangle = grdApps.GetCellDisplayRectangle(0, (int)control.Tag, cutOverflow: false);
control.Location = cellDisplayRectangle.Location;
control.Size = cellDisplayRectangle.Size;
control.BringToFront();
}
}
}
public void Clear()
{
mAppGroups.Clear();
grdApps.Rows.Clear();
grdApps.Controls.Clear();
}
public void SetData(IEnumerable<PodAppInstance> instances)
{
Clear();
foreach (PodAppInstance instance in instances)
{
if (!mAppGroups.TryGetValue(instance.LaunchPair.LaunchKey, out var value))
{
value = new ApplicationInstanceGroup(instance.LaunchPair);
mAppGroups.Add(instance.LaunchPair.LaunchKey, value);
}
value.AddInstance(instance);
}
Refresh();
grdApps.Sort(grdApps.Columns[2], ListSortDirection.Ascending);
}
public void StartApp(Guid podId, Guid appId)
{
if (mAppGroups.ContainsKey(appId))
{
ApplicationInstanceGroup applicationInstanceGroup = mAppGroups[appId];
applicationInstanceGroup.StartPod(podId);
RefreshAppGroup(applicationInstanceGroup);
Resort();
}
}
public void StartAppFailed(Guid appId, string podDisplayName)
{
if (mAppGroups.ContainsKey(appId))
{
ApplicationInstanceGroup applicationInstanceGroup = mAppGroups[appId];
FlagError(applicationInstanceGroup.StoppedKey, podDisplayName, "The following pods failed to stop:");
}
}
public void StopApp(Guid podId, Guid appId)
{
if (mAppGroups.ContainsKey(appId))
{
ApplicationInstanceGroup applicationInstanceGroup = mAppGroups[appId];
applicationInstanceGroup.StopPod(podId);
RefreshAppGroup(applicationInstanceGroup);
Resort();
}
}
public void StopAppFailed(Guid appId, string podDisplayName)
{
if (mAppGroups.ContainsKey(appId))
{
ApplicationInstanceGroup applicationInstanceGroup = mAppGroups[appId];
FlagError(applicationInstanceGroup.RunningKey, podDisplayName, "The following pods failed to stop:");
}
}
private void FlagError(string rowKey, string podDisplayName, string error)
{
Control[] array = grdApps.Controls.Find(rowKey, searchAllChildren: false);
foreach (Control value in array)
{
grdApps.Controls.Remove(value);
}
foreach (DataGridViewRow item in (IEnumerable)grdApps.Rows)
{
if (object.Equals(item.Tag, rowKey))
{
((List<string>)item.Cells[3].Tag).Add(podDisplayName);
RefreshRowError(item, error);
}
}
}
public override void Refresh()
{
base.Refresh();
grdApps.SuspendLayout();
foreach (ApplicationInstanceGroup value in mAppGroups.Values)
{
RefreshAppGroup(value);
}
grdApps.ResumeLayout();
grdApps.AutoResizeColumns();
Resort();
}
private void RefreshAppGroup(ApplicationInstanceGroup group)
{
bool flag = false;
bool flag2 = false;
for (int num = grdApps.Rows.Count - 1; num >= 0; num--)
{
DataGridViewRow dataGridViewRow = grdApps.Rows[num];
if (object.Equals(dataGridViewRow.Tag, group.RunningKey))
{
flag = true;
if (group.RunningPods.Count > 0)
{
RefreshRow(dataGridViewRow, isRunning: true, group.RunningPods.Count);
}
else
{
RemoveRow(num);
}
}
else if (object.Equals(dataGridViewRow.Tag, group.StoppedKey))
{
flag2 = true;
if (group.StoppedPods.Count > 0)
{
RefreshRow(dataGridViewRow, isRunning: false, group.StoppedPods.Count);
}
else
{
RemoveRow(num);
}
}
}
if (!flag && group.RunningPods.Count > 0)
{
grdApps.Rows.Add(CreateRow(group, isRunning: true));
}
if (!flag2 && group.StoppedPods.Count > 0)
{
grdApps.Rows.Add(CreateRow(group, isRunning: false));
}
}
private void Resort()
{
if (grdApps.SortOrder != 0)
{
grdApps.Sort(grdApps.SortedColumn, (grdApps.SortOrder != SortOrder.Ascending) ? ListSortDirection.Descending : ListSortDirection.Ascending);
}
}
private DataGridViewRow CreateRow(ApplicationInstanceGroup group, bool isRunning)
{
DataGridViewRow dataGridViewRow = new DataGridViewRow();
dataGridViewRow.Tag = (isRunning ? group.RunningKey : group.StoppedKey);
dataGridViewRow.Cells.Add(new DataGridViewLinkCell());
dataGridViewRow.Cells.Add(new DataGridViewTextBoxCell());
DataGridViewTextBoxCell dataGridViewTextBoxCell = new DataGridViewTextBoxCell();
dataGridViewTextBoxCell.Value = group.AppDisplayName;
dataGridViewRow.Cells.Add(dataGridViewTextBoxCell);
DataGridViewImageCell dataGridViewImageCell = new DataGridViewImageCell();
dataGridViewImageCell.Value = Resources.Blank;
dataGridViewImageCell.Tag = new List<string>();
dataGridViewRow.Cells.Add(dataGridViewImageCell);
RefreshRow(dataGridViewRow, isRunning, isRunning ? group.RunningPods.Count : group.StoppedPods.Count);
return dataGridViewRow;
}
private void RefreshRow(DataGridViewRow row, bool isRunning, int count)
{
DataGridViewLinkCell dataGridViewLinkCell = (DataGridViewLinkCell)row.Cells[0];
dataGridViewLinkCell.Value = (isRunning ? "Stop" : "Start");
Color color2 = (dataGridViewLinkCell.VisitedLinkColor = (isRunning ? Color.Red : Color.Green));
Color color5 = (dataGridViewLinkCell.LinkColor = (dataGridViewLinkCell.ActiveLinkColor = color2));
DataGridViewTextBoxCell dataGridViewTextBoxCell = (DataGridViewTextBoxCell)row.Cells[1];
if (ShowCounts)
{
dataGridViewTextBoxCell.Value = count + (isRunning ? " Running" : " Stopped");
}
else
{
dataGridViewTextBoxCell.Value = (isRunning ? "Running" : "Stopped");
}
dataGridViewTextBoxCell.Style.ForeColor = (isRunning ? Color.Green : Color.Black);
}
private void RefreshRowError(DataGridViewRow row, string errorPrefix)
{
row.Cells[3].Value = Resources.Error;
StringBuilder stringBuilder = new StringBuilder(errorPrefix);
foreach (string item in (List<string>)row.Cells[3].Tag)
{
stringBuilder.AppendLine();
stringBuilder.Append(" - ");
stringBuilder.Append(item);
}
row.Cells[3].ToolTipText = stringBuilder.ToString();
}
private void RemoveRow(int index)
{
Control[] array = grdApps.Controls.Find((string)grdApps.Rows[index].Tag, searchAllChildren: false);
foreach (Control value in array)
{
grdApps.Controls.Remove(value);
}
grdApps.Rows.RemoveAt(index);
}
protected override void Dispose(bool disposing)
{
if (disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
private void InitializeComponent()
{
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle2 = new System.Windows.Forms.DataGridViewCellStyle();
System.Windows.Forms.DataGridViewCellStyle dataGridViewCellStyle3 = new System.Windows.Forms.DataGridViewCellStyle();
this.grdApps = new TeslaConsole.NoSelectDataGridView();
this.colAction = new System.Windows.Forms.DataGridViewLinkColumn();
this.colStatus = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colName = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.colError = new System.Windows.Forms.DataGridViewImageColumn();
((System.ComponentModel.ISupportInitialize)this.grdApps).BeginInit();
base.SuspendLayout();
this.grdApps.AllowUserToAddRows = false;
this.grdApps.AllowUserToDeleteRows = false;
this.grdApps.AllowUserToResizeRows = false;
this.grdApps.BackgroundColor = System.Drawing.Color.White;
this.grdApps.BorderStyle = System.Windows.Forms.BorderStyle.None;
this.grdApps.CellBorderStyle = System.Windows.Forms.DataGridViewCellBorderStyle.None;
this.grdApps.ColumnHeadersBorderStyle = System.Windows.Forms.DataGridViewHeaderBorderStyle.Single;
this.grdApps.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize;
this.grdApps.Columns.AddRange(this.colAction, this.colStatus, this.colName, this.colError);
this.grdApps.Dock = System.Windows.Forms.DockStyle.Fill;
this.grdApps.EditMode = System.Windows.Forms.DataGridViewEditMode.EditProgrammatically;
this.grdApps.GridColor = System.Drawing.Color.White;
this.grdApps.Location = new System.Drawing.Point(0, 0);
this.grdApps.MultiSelect = false;
this.grdApps.Name = "grdApps";
this.grdApps.ReadOnly = true;
this.grdApps.RowHeadersVisible = false;
this.grdApps.ScrollBars = System.Windows.Forms.ScrollBars.Vertical;
this.grdApps.SelectionMode = System.Windows.Forms.DataGridViewSelectionMode.FullRowSelect;
this.grdApps.Size = new System.Drawing.Size(366, 215);
this.grdApps.TabIndex = 8;
this.grdApps.Scroll += new System.Windows.Forms.ScrollEventHandler(grdApps_Scroll);
this.grdApps.CellContentClick += new System.Windows.Forms.DataGridViewCellEventHandler(grdApps_CellContentClick);
this.colAction.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
dataGridViewCellStyle.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
this.colAction.DefaultCellStyle = dataGridViewCellStyle;
this.colAction.Frozen = true;
this.colAction.HeaderText = "Action";
this.colAction.LinkColor = System.Drawing.Color.Blue;
this.colAction.MinimumWidth = 50;
this.colAction.Name = "colAction";
this.colAction.ReadOnly = true;
this.colAction.VisitedLinkColor = System.Drawing.Color.Blue;
this.colAction.Width = 50;
this.colStatus.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.AllCells;
dataGridViewCellStyle2.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleCenter;
dataGridViewCellStyle2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25f, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, 0);
this.colStatus.DefaultCellStyle = dataGridViewCellStyle2;
this.colStatus.Frozen = true;
this.colStatus.HeaderText = "Status";
this.colStatus.MinimumWidth = 50;
this.colStatus.Name = "colStatus";
this.colStatus.ReadOnly = true;
this.colStatus.Width = 62;
this.colName.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill;
dataGridViewCellStyle3.Alignment = System.Windows.Forms.DataGridViewContentAlignment.MiddleLeft;
this.colName.DefaultCellStyle = dataGridViewCellStyle3;
this.colName.HeaderText = "Application Name";
this.colName.MinimumWidth = 100;
this.colName.Name = "colName";
this.colName.ReadOnly = true;
this.colError.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.None;
this.colError.HeaderText = "";
this.colError.MinimumWidth = 20;
this.colError.Name = "colError";
this.colError.ReadOnly = true;
this.colError.Width = 20;
base.AutoScaleDimensions = new System.Drawing.SizeF(6f, 13f);
base.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
base.Controls.Add(this.grdApps);
base.Name = "AppControlGrid";
base.Size = new System.Drawing.Size(366, 215);
((System.ComponentModel.ISupportInitialize)this.grdApps).EndInit();
base.ResumeLayout(false);
}
}