mirror of
https://github.com/tgstation/tgstation-server.git
synced 2026-08-27 07:04:57 +01:00
Control Panel instance manager
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
using TGServiceInterface;
|
||||
@@ -8,8 +9,13 @@ namespace TGControlPanel
|
||||
/// <summary>
|
||||
/// The main <see cref="ControlPanel"/> form
|
||||
/// </summary>
|
||||
partial class ControlPanel : Form
|
||||
partial class ControlPanel : CountedForm
|
||||
{
|
||||
/// <summary>
|
||||
/// List of instances being used by open control panels
|
||||
/// </summary>
|
||||
public static IDictionary<string, ControlPanel> InstancesInUse { get; private set; } = new Dictionary<string, ControlPanel>();
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="TGServiceInterface.Interface"/> instance for this <see cref="ControlPanel"/>
|
||||
/// </summary>
|
||||
@@ -35,6 +41,7 @@ namespace TGControlPanel
|
||||
InitServerPage();
|
||||
LoadChatPage();
|
||||
InitStaticPage();
|
||||
InstancesInUse.Add(I.InstanceName, this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -42,6 +49,7 @@ namespace TGControlPanel
|
||||
/// </summary>
|
||||
void Cleanup()
|
||||
{
|
||||
InstancesInUse.Remove(Interface.InstanceName);
|
||||
Interface.Dispose();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
/// <summary>
|
||||
/// Calls <see cref="Application.Exit"/> when all <see cref="CountedForm"/>s are <see cref="Form.Close"/>d
|
||||
/// </summary>
|
||||
class CountedForm : Form
|
||||
{
|
||||
/// <summary>
|
||||
/// The current number of active <see cref="CountedForm"/>s
|
||||
/// </summary>
|
||||
static uint FormCount;
|
||||
|
||||
/// <summary>
|
||||
/// Construct a <see cref="CountedForm"/>. Increments <see cref="FormCount"/>
|
||||
/// </summary>
|
||||
public CountedForm()
|
||||
{
|
||||
FormClosed += CountedForm_FormClosed;
|
||||
++FormCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Decrements <see cref="FormCount"/>. Calls <see cref="Application.Exit"/> if it reaches 0
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="FormClosedEventArgs"/></param>
|
||||
private void CountedForm_FormClosed(object sender, FormClosedEventArgs e)
|
||||
{
|
||||
if (--FormCount == 0)
|
||||
Application.Exit();
|
||||
}
|
||||
}
|
||||
}
|
||||
+134
@@ -0,0 +1,134 @@
|
||||
namespace TGControlPanel
|
||||
{
|
||||
partial class InstanceSelector
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
Cleanup();
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(InstanceSelector));
|
||||
this.InstanceListBox = new System.Windows.Forms.ListBox();
|
||||
this.CreateInstanceButton = new System.Windows.Forms.Button();
|
||||
this.ImportInstanceButton = new System.Windows.Forms.Button();
|
||||
this.RenameInstanceButton = new System.Windows.Forms.Button();
|
||||
this.DetachInstanceButton = new System.Windows.Forms.Button();
|
||||
this.RefreshButton = new System.Windows.Forms.Button();
|
||||
this.SuspendLayout();
|
||||
//
|
||||
// InstanceListBox
|
||||
//
|
||||
this.InstanceListBox.Anchor = System.Windows.Forms.AnchorStyles.Left;
|
||||
this.InstanceListBox.FormattingEnabled = true;
|
||||
this.InstanceListBox.Location = new System.Drawing.Point(13, 13);
|
||||
this.InstanceListBox.Name = "InstanceListBox";
|
||||
this.InstanceListBox.Size = new System.Drawing.Size(339, 238);
|
||||
this.InstanceListBox.TabIndex = 0;
|
||||
//
|
||||
// CreateInstanceButton
|
||||
//
|
||||
this.CreateInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.CreateInstanceButton.Location = new System.Drawing.Point(358, 15);
|
||||
this.CreateInstanceButton.Name = "CreateInstanceButton";
|
||||
this.CreateInstanceButton.Size = new System.Drawing.Size(148, 25);
|
||||
this.CreateInstanceButton.TabIndex = 14;
|
||||
this.CreateInstanceButton.Text = "Create Instance";
|
||||
this.CreateInstanceButton.UseVisualStyleBackColor = true;
|
||||
this.CreateInstanceButton.Click += new System.EventHandler(this.CreateInstanceButton_Click);
|
||||
//
|
||||
// ImportInstanceButton
|
||||
//
|
||||
this.ImportInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.ImportInstanceButton.Location = new System.Drawing.Point(358, 45);
|
||||
this.ImportInstanceButton.Name = "ImportInstanceButton";
|
||||
this.ImportInstanceButton.Size = new System.Drawing.Size(148, 25);
|
||||
this.ImportInstanceButton.TabIndex = 15;
|
||||
this.ImportInstanceButton.Text = "Import Instance";
|
||||
this.ImportInstanceButton.UseVisualStyleBackColor = true;
|
||||
this.ImportInstanceButton.Click += new System.EventHandler(this.ImportInstanceButton_Click);
|
||||
//
|
||||
// RenameInstanceButton
|
||||
//
|
||||
this.RenameInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.RenameInstanceButton.Location = new System.Drawing.Point(358, 76);
|
||||
this.RenameInstanceButton.Name = "RenameInstanceButton";
|
||||
this.RenameInstanceButton.Size = new System.Drawing.Size(148, 25);
|
||||
this.RenameInstanceButton.TabIndex = 16;
|
||||
this.RenameInstanceButton.Text = "Rename Instance";
|
||||
this.RenameInstanceButton.UseVisualStyleBackColor = true;
|
||||
this.RenameInstanceButton.Click += new System.EventHandler(this.RenameInstanceButton_Click);
|
||||
//
|
||||
// DetachInstanceButton
|
||||
//
|
||||
this.DetachInstanceButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.DetachInstanceButton.Location = new System.Drawing.Point(358, 107);
|
||||
this.DetachInstanceButton.Name = "DetachInstanceButton";
|
||||
this.DetachInstanceButton.Size = new System.Drawing.Size(148, 25);
|
||||
this.DetachInstanceButton.TabIndex = 17;
|
||||
this.DetachInstanceButton.Text = "Detach Instance";
|
||||
this.DetachInstanceButton.UseVisualStyleBackColor = true;
|
||||
this.DetachInstanceButton.Click += new System.EventHandler(this.DetachInstanceButton_Click);
|
||||
//
|
||||
// RefreshButton
|
||||
//
|
||||
this.RefreshButton.Anchor = System.Windows.Forms.AnchorStyles.Right;
|
||||
this.RefreshButton.Location = new System.Drawing.Point(358, 226);
|
||||
this.RefreshButton.Name = "RefreshButton";
|
||||
this.RefreshButton.Size = new System.Drawing.Size(148, 25);
|
||||
this.RefreshButton.TabIndex = 19;
|
||||
this.RefreshButton.Text = "Refresh";
|
||||
this.RefreshButton.UseVisualStyleBackColor = true;
|
||||
this.RefreshButton.Click += new System.EventHandler(this.RefreshButton_Click);
|
||||
//
|
||||
// InstanceSelector
|
||||
//
|
||||
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
|
||||
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(39)))), ((int)(((byte)(40)))), ((int)(((byte)(34)))));
|
||||
this.ClientSize = new System.Drawing.Size(518, 261);
|
||||
this.Controls.Add(this.RefreshButton);
|
||||
this.Controls.Add(this.DetachInstanceButton);
|
||||
this.Controls.Add(this.RenameInstanceButton);
|
||||
this.Controls.Add(this.ImportInstanceButton);
|
||||
this.Controls.Add(this.CreateInstanceButton);
|
||||
this.Controls.Add(this.InstanceListBox);
|
||||
this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
|
||||
this.Name = "InstanceSelector";
|
||||
this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
|
||||
this.Text = "Server Instances";
|
||||
this.ResumeLayout(false);
|
||||
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ListBox InstanceListBox;
|
||||
private System.Windows.Forms.Button CreateInstanceButton;
|
||||
private System.Windows.Forms.Button ImportInstanceButton;
|
||||
private System.Windows.Forms.Button RenameInstanceButton;
|
||||
private System.Windows.Forms.Button DetachInstanceButton;
|
||||
private System.Windows.Forms.Button RefreshButton;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,214 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using TGServiceInterface;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
/// <summary>
|
||||
/// Form used for managing <see cref="TGServiceInterface.Components.ITGSService"/> <see cref="TGServiceInterface.Components.ITGInstance"/> manipulation functions
|
||||
/// </summary>
|
||||
partial class InstanceSelector : CountedForm
|
||||
{
|
||||
/// <summary>
|
||||
/// The <see cref="Interface"/> we build instance connections from
|
||||
/// </summary>
|
||||
readonly Interface masterInterface;
|
||||
/// <summary>
|
||||
/// List of <see cref="InstanceMetadata"/> from <see cref="masterInterface"/>
|
||||
/// </summary>
|
||||
IList<InstanceMetadata> InstanceData;
|
||||
public InstanceSelector(Interface I)
|
||||
{
|
||||
InitializeComponent();
|
||||
InstanceListBox.MouseDoubleClick += InstanceListBox_MouseDoubleClick;
|
||||
masterInterface = I;
|
||||
RefreshInstances();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used to wrap <see cref="Interface"/> calls in a non-blocking fashion
|
||||
/// </summary>
|
||||
/// <param name="action">The <see cref="Interface"/> operation to wrap</param>
|
||||
Task WrapServerOp(Action action)
|
||||
{
|
||||
Enabled = false;
|
||||
UseWaitCursor = true;
|
||||
try
|
||||
{
|
||||
return Task.Factory.StartNew(action);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Enabled = true;
|
||||
UseWaitCursor = false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Connects to a <see cref="TGServiceInterface.Components.ITGInstance"/> if it is double clicked in <see cref="InstanceListBox"/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="MouseEventArgs"/></param>
|
||||
void InstanceListBox_MouseDoubleClick(object sender, MouseEventArgs e)
|
||||
{
|
||||
var index = InstanceListBox.IndexFromPoint(e.Location);
|
||||
if (index != ListBox.NoMatches)
|
||||
TryConnectToInstance(InstanceData[index].Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the <see cref="InstanceMetadata"/> associated with <see cref="InstanceListBox"/>'s current selected index
|
||||
/// </summary>
|
||||
/// <returns>The <see cref="InstanceMetadata"/> associated with <see cref="InstanceListBox"/>'s current selected index if it exists, <see langword="null"/> otherwise</returns>
|
||||
InstanceMetadata GetSelectedInstanceMetadata()
|
||||
{
|
||||
var index = InstanceListBox.SelectedIndex;
|
||||
return index != ListBox.NoMatches ? InstanceData[index] : null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by <see cref="Dispose(bool)"/>
|
||||
/// </summary>
|
||||
void Cleanup()
|
||||
{
|
||||
masterInterface.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads the <see cref="InstanceListBox"/> using <see cref="TGServiceInterface.Components.ITGSService.ListInstances"/>
|
||||
/// </summary>
|
||||
async void RefreshInstances()
|
||||
{
|
||||
InstanceListBox.Items.Clear();
|
||||
await WrapServerOp(() => {
|
||||
InstanceData = masterInterface.GetService().ListInstances();
|
||||
});
|
||||
foreach(var I in InstanceData)
|
||||
InstanceListBox.Items.Add(String.Format("{0}: {1} - {2} - {3}", I.LoggingID, I.Name, I.Path, I.Enabled ? "ONLINE" : "OFFLINE"));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tries to start a <see cref="ControlPanel"/> for a given <paramref name="instanceName"/>
|
||||
/// </summary>
|
||||
/// <param name="instanceName">The name of the <see cref="TGServiceInterface.Components.ITGInstance"/> to connect to</param>
|
||||
async void TryConnectToInstance(string instanceName)
|
||||
{
|
||||
var activeCP = ControlPanel.InstancesInUse[instanceName];
|
||||
if(activeCP != null)
|
||||
{
|
||||
activeCP.BringToFront();
|
||||
return;
|
||||
}
|
||||
var InstanceAccessor = new Interface(masterInterface);
|
||||
try
|
||||
{
|
||||
ConnectivityLevel res = ConnectivityLevel.None;
|
||||
await WrapServerOp(() => { res = InstanceAccessor.ConnectToInstance(instanceName); });
|
||||
if (!res.HasFlag(ConnectivityLevel.Connected))
|
||||
{
|
||||
MessageBox.Show("Unable to connect to instance! Does it exist?");
|
||||
RefreshInstances();
|
||||
}
|
||||
else if (!res.HasFlag(ConnectivityLevel.Authenticated))
|
||||
MessageBox.Show("The current user is not authorized to access this instance!");
|
||||
else
|
||||
new ControlPanel(InstanceAccessor).Show();
|
||||
}
|
||||
catch
|
||||
{
|
||||
InstanceAccessor.Dispose();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.DetachInstance(string)"/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/></param>
|
||||
async void DetachInstanceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var imd = GetSelectedInstanceMetadata();
|
||||
if (imd == null)
|
||||
return;
|
||||
if (MessageBox.Show(String.Format("This will dissociate the server instance at \"{0}\"! Are you sure?", imd.Path), "Instance Detach", MessageBoxButtons.YesNo) != DialogResult.Yes)
|
||||
return;
|
||||
string res = null;
|
||||
await WrapServerOp(() => { res = masterInterface.GetService().DetachInstance(imd.Name); });
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
RefreshInstances();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Calls <see cref="RefreshInstances"/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/></param>
|
||||
void RefreshButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
RefreshInstances();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.RenameInstance(string, string)"/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/></param>
|
||||
async void RenameInstanceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var imd = GetSelectedInstanceMetadata();
|
||||
if (imd == null)
|
||||
return;
|
||||
var new_name = Program.TextPrompt("Instance Rename", "Enter a new name for the instance:");
|
||||
if (new_name == null)
|
||||
return;
|
||||
if (imd.Enabled && MessageBox.Show(String.Format("This will temporarily offline the server instance! Are you sure?", imd.Path), "Instance Restart", MessageBoxButtons.YesNo) != DialogResult.Yes)
|
||||
return;
|
||||
string res = null;
|
||||
await WrapServerOp(() => { res = masterInterface.GetService().RenameInstance(imd.Name, new_name); });
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
RefreshInstances();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.ImportInstance(string)/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/></param>
|
||||
async void ImportInstanceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var instance_path = Program.TextPrompt("Instance Import", "Enter the full path to the instance:");
|
||||
if (instance_path == null)
|
||||
return;
|
||||
string res = null;
|
||||
await WrapServerOp(() => { res = masterInterface.GetService().ImportInstance(instance_path); });
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
RefreshInstances();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user for parameters to <see cref="TGServiceInterface.Components.ITGSService.CreateInstance(string, string)/>
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of the event</param>
|
||||
/// <param name="e">The <see cref="EventArgs"/></param>
|
||||
async void CreateInstanceButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
var instance_name = Program.TextPrompt("Instance Creation", "Enter the name of the instance:");
|
||||
if (instance_name == null)
|
||||
return;
|
||||
var instance_path = Program.TextPrompt("Instance Creation", "Enter the full path to the instance:");
|
||||
if (instance_path == null)
|
||||
return;
|
||||
string res = null;
|
||||
await WrapServerOp(() => { res = masterInterface.GetService().CreateInstance(instance_name, instance_path); });
|
||||
if (res != null)
|
||||
MessageBox.Show(res);
|
||||
RefreshInstances();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
+41
-17
@@ -4,7 +4,7 @@ using TGServiceInterface;
|
||||
|
||||
namespace TGControlPanel
|
||||
{
|
||||
partial class Login : Form
|
||||
partial class Login : CountedForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a <see cref="Login"/> form
|
||||
@@ -53,30 +53,54 @@ namespace TGControlPanel
|
||||
|
||||
private void LocalLoginButton_Click(object sender, EventArgs e)
|
||||
{
|
||||
using (var I = new Interface())
|
||||
{
|
||||
Properties.Settings.Default.RemoteDefault = false;
|
||||
VerifyAndConnect(I);
|
||||
}
|
||||
Properties.Settings.Default.RemoteDefault = false;
|
||||
VerifyAndConnect(new Interface());
|
||||
}
|
||||
|
||||
void VerifyAndConnect(Interface I)
|
||||
{
|
||||
var res = I.ConnectionStatus(out string error);
|
||||
if (!res.HasFlag(ConnectivityLevel.Connected))
|
||||
try
|
||||
{
|
||||
MessageBox.Show("Unable to connect to service! Error: " + error);
|
||||
return;
|
||||
var res = I.ConnectionStatus(out string error);
|
||||
if (!res.HasFlag(ConnectivityLevel.Connected))
|
||||
{
|
||||
MessageBox.Show("Unable to connect to service! Error: " + error);
|
||||
return;
|
||||
}
|
||||
if (!res.HasFlag(ConnectivityLevel.Authenticated))
|
||||
{
|
||||
MessageBox.Show("Authentication error: Username/password/windows identity is not authorized! Ensure you are a system administrator or in the correct Windows group on the service machine.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res.HasFlag(ConnectivityLevel.Administrator))
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
var InstanceToConnectTo = Program.TextPrompt("Select instance", "You do not have permission to list server instances. Please enter the name of the instance to connect to:");
|
||||
if (InstanceToConnectTo == null)
|
||||
return;
|
||||
|
||||
res = I.ConnectToInstance(InstanceToConnectTo);
|
||||
if (!res.HasFlag(ConnectivityLevel.Connected))
|
||||
MessageBox.Show("Unable to connect to instance! Does it exist?");
|
||||
else if (!res.HasFlag(ConnectivityLevel.Authenticated))
|
||||
MessageBox.Show("The current user is not authorized to access this instance!");
|
||||
else
|
||||
break;
|
||||
}
|
||||
|
||||
new ControlPanel(I).Show();
|
||||
}
|
||||
else
|
||||
new InstanceSelector(I).Show();
|
||||
Close();
|
||||
}
|
||||
if (!res.HasFlag(ConnectivityLevel.Authenticated))
|
||||
catch
|
||||
{
|
||||
MessageBox.Show("Authentication error: Username/password/windows identity is not authorized! Ensure you are a system administrator or in the correct Windows group on the service machine.");
|
||||
return;
|
||||
I.Dispose();
|
||||
throw;
|
||||
}
|
||||
Hide();
|
||||
using (var M = new ControlPanel(I))
|
||||
M.ShowDialog();
|
||||
Close();
|
||||
}
|
||||
|
||||
private void SavePasswordCheckBox_CheckedChanged(object sender, EventArgs e)
|
||||
|
||||
@@ -19,8 +19,9 @@ namespace TGControlPanel
|
||||
}
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
using(var L = new Login())
|
||||
Application.Run(L);
|
||||
var login = new Login();
|
||||
login.Show();
|
||||
Application.Run();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@@ -55,6 +55,15 @@
|
||||
<Compile Include="ControlPanel\ChatPage.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="CountedForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="InstanceSelector.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Include="InstanceSelector.Designer.cs">
|
||||
<DependentUpon>InstanceSelector.cs</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Login.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@@ -84,6 +93,9 @@
|
||||
<Compile Include="ControlPanel\StaticPage.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<EmbeddedResource Include="InstanceSelector.resx">
|
||||
<DependentUpon>InstanceSelector.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Login.resx">
|
||||
<DependentUpon>Login.cs</DependentUpon>
|
||||
</EmbeddedResource>
|
||||
|
||||
Reference in New Issue
Block a user