Files
scadalink-design/src/ScadaLink.CLI/Commands/SiteCommands.cs
Joseph Doherty c63fb1c4a6 feat: achieve CLI parity with Central UI
Add 33 new management message records, ManagementActor handlers, and CLI
commands to close all functionality gaps between the Central UI and the
Management CLI. New capabilities include:

- Template member CRUD (attributes, alarms, scripts, compositions)
- Shared script CRUD
- Database connection definition CRUD
- Inbound API method CRUD
- LDAP scope rule management
- API key enable/disable
- Area update
- Remote event log and parked message queries
- Missing get/update commands for templates, sites, instances, data
  connections, external systems, notifications, and SMTP config

Includes 12 new ManagementActor unit tests covering authorization,
happy-path queries, and error handling. Updates CLI README and component
design documents (Component-CLI.md, Component-ManagementService.md).
2026-03-18 01:21:20 -04:00

194 lines
8.8 KiB
C#

using System.CommandLine;
using System.CommandLine.Parsing;
using ScadaLink.Commons.Messages.Management;
namespace ScadaLink.CLI.Commands;
public static class SiteCommands
{
public static Command Build(Option<string> contactPointsOption, Option<string> formatOption)
{
var command = new Command("site") { Description = "Manage sites" };
command.Add(BuildList(contactPointsOption, formatOption));
command.Add(BuildGet(contactPointsOption, formatOption));
command.Add(BuildCreate(contactPointsOption, formatOption));
command.Add(BuildUpdate(contactPointsOption, formatOption));
command.Add(BuildDelete(contactPointsOption, formatOption));
command.Add(BuildDeployArtifacts(contactPointsOption, formatOption));
command.Add(BuildArea(contactPointsOption, formatOption));
return command;
}
private static Command BuildGet(Option<string> contactPointsOption, Option<string> formatOption)
{
var idOption = new Option<int>("--id") { Description = "Site ID", Required = true };
var cmd = new Command("get") { Description = "Get a site by ID" };
cmd.Add(idOption);
cmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(idOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new GetSiteCommand(id));
});
return cmd;
}
private static Command BuildList(Option<string> contactPointsOption, Option<string> formatOption)
{
var cmd = new Command("list") { Description = "List all sites" };
cmd.SetAction(async (ParseResult result) =>
{
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new ListSitesCommand());
});
return cmd;
}
private static Command BuildCreate(Option<string> contactPointsOption, Option<string> formatOption)
{
var nameOption = new Option<string>("--name") { Description = "Site name", Required = true };
var identifierOption = new Option<string>("--identifier") { Description = "Site identifier", Required = true };
var descOption = new Option<string?>("--description") { Description = "Site description" };
var nodeAOption = new Option<string?>("--node-a-address") { Description = "Akka address for Node A" };
var nodeBOption = new Option<string?>("--node-b-address") { Description = "Akka address for Node B" };
var cmd = new Command("create") { Description = "Create a new site" };
cmd.Add(nameOption);
cmd.Add(identifierOption);
cmd.Add(descOption);
cmd.Add(nodeAOption);
cmd.Add(nodeBOption);
cmd.SetAction(async (ParseResult result) =>
{
var name = result.GetValue(nameOption)!;
var identifier = result.GetValue(identifierOption)!;
var desc = result.GetValue(descOption);
var nodeA = result.GetValue(nodeAOption);
var nodeB = result.GetValue(nodeBOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption,
new CreateSiteCommand(name, identifier, desc, nodeA, nodeB));
});
return cmd;
}
private static Command BuildUpdate(Option<string> contactPointsOption, Option<string> formatOption)
{
var idOption = new Option<int>("--id") { Description = "Site ID", Required = true };
var nameOption = new Option<string>("--name") { Description = "Site name", Required = true };
var descOption = new Option<string?>("--description") { Description = "Site description" };
var nodeAOption = new Option<string?>("--node-a-address") { Description = "Akka address for Node A" };
var nodeBOption = new Option<string?>("--node-b-address") { Description = "Akka address for Node B" };
var cmd = new Command("update") { Description = "Update an existing site" };
cmd.Add(idOption);
cmd.Add(nameOption);
cmd.Add(descOption);
cmd.Add(nodeAOption);
cmd.Add(nodeBOption);
cmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(idOption);
var name = result.GetValue(nameOption)!;
var desc = result.GetValue(descOption);
var nodeA = result.GetValue(nodeAOption);
var nodeB = result.GetValue(nodeBOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption,
new UpdateSiteCommand(id, name, desc, nodeA, nodeB));
});
return cmd;
}
private static Command BuildDelete(Option<string> contactPointsOption, Option<string> formatOption)
{
var idOption = new Option<int>("--id") { Description = "Site ID", Required = true };
var cmd = new Command("delete") { Description = "Delete a site" };
cmd.Add(idOption);
cmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(idOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new DeleteSiteCommand(id));
});
return cmd;
}
private static Command BuildArea(Option<string> contactPointsOption, Option<string> formatOption)
{
var group = new Command("area") { Description = "Manage areas" };
var siteIdOption = new Option<int>("--site-id") { Description = "Site ID", Required = true };
var listCmd = new Command("list") { Description = "List areas for a site" };
listCmd.Add(siteIdOption);
listCmd.SetAction(async (ParseResult result) =>
{
var siteId = result.GetValue(siteIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new ListAreasCommand(siteId));
});
group.Add(listCmd);
var createSiteIdOption = new Option<int>("--site-id") { Description = "Site ID", Required = true };
var nameOption = new Option<string>("--name") { Description = "Area name", Required = true };
var parentOption = new Option<int?>("--parent-id") { Description = "Parent area ID" };
var createCmd = new Command("create") { Description = "Create an area" };
createCmd.Add(createSiteIdOption);
createCmd.Add(nameOption);
createCmd.Add(parentOption);
createCmd.SetAction(async (ParseResult result) =>
{
var siteId = result.GetValue(createSiteIdOption);
var name = result.GetValue(nameOption)!;
var parentId = result.GetValue(parentOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption,
new CreateAreaCommand(siteId, name, parentId));
});
group.Add(createCmd);
var updateIdOption = new Option<int>("--id") { Description = "Area ID", Required = true };
var updateNameOption = new Option<string>("--name") { Description = "New area name", Required = true };
var updateCmd = new Command("update") { Description = "Update an area" };
updateCmd.Add(updateIdOption);
updateCmd.Add(updateNameOption);
updateCmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(updateIdOption);
var name = result.GetValue(updateNameOption)!;
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new UpdateAreaCommand(id, name));
});
group.Add(updateCmd);
var deleteIdOption = new Option<int>("--id") { Description = "Area ID", Required = true };
var deleteCmd = new Command("delete") { Description = "Delete an area" };
deleteCmd.Add(deleteIdOption);
deleteCmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(deleteIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new DeleteAreaCommand(id));
});
group.Add(deleteCmd);
return group;
}
private static Command BuildDeployArtifacts(Option<string> contactPointsOption, Option<string> formatOption)
{
var siteIdOption = new Option<int?>("--site-id") { Description = "Target site ID (all sites if omitted)" };
var cmd = new Command("deploy-artifacts") { Description = "Deploy artifacts to site(s)" };
cmd.Add(siteIdOption);
cmd.SetAction(async (ParseResult result) =>
{
var siteId = result.GetValue(siteIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new MgmtDeployArtifactsCommand(siteId));
});
return cmd;
}
}