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>
This commit is contained in:
@@ -0,0 +1,473 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user