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).
This commit is contained in:
Joseph Doherty
2026-03-18 01:21:20 -04:00
parent b2385709f8
commit c63fb1c4a6
24 changed files with 2500 additions and 15 deletions

View File

@@ -12,6 +12,7 @@ public static class SecurityCommands
command.Add(BuildApiKey(contactPointsOption, formatOption));
command.Add(BuildRoleMapping(contactPointsOption, formatOption));
command.Add(BuildScopeRule(contactPointsOption, formatOption));
return command;
}
@@ -50,6 +51,20 @@ public static class SecurityCommands
});
group.Add(deleteCmd);
var updateIdOption = new Option<int>("--id") { Description = "API key ID", Required = true };
var enabledOption = new Option<bool>("--enabled") { Description = "Enable or disable", Required = true };
var updateCmd = new Command("update") { Description = "Enable or disable an API key" };
updateCmd.Add(updateIdOption);
updateCmd.Add(enabledOption);
updateCmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(updateIdOption);
var enabled = result.GetValue(enabledOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new UpdateApiKeyCommand(id, enabled));
});
group.Add(updateCmd);
return group;
}
@@ -91,6 +106,67 @@ public static class SecurityCommands
});
group.Add(deleteCmd);
var updateIdOption = new Option<int>("--id") { Description = "Mapping ID", Required = true };
var updateLdapGroupOption = new Option<string>("--ldap-group") { Description = "LDAP group name", Required = true };
var updateRoleOption = new Option<string>("--role") { Description = "Role name", Required = true };
var updateCmd = new Command("update") { Description = "Update a role mapping" };
updateCmd.Add(updateIdOption);
updateCmd.Add(updateLdapGroupOption);
updateCmd.Add(updateRoleOption);
updateCmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(updateIdOption);
var ldapGroup = result.GetValue(updateLdapGroupOption)!;
var role = result.GetValue(updateRoleOption)!;
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption,
new UpdateRoleMappingCommand(id, ldapGroup, role));
});
group.Add(updateCmd);
return group;
}
private static Command BuildScopeRule(Option<string> contactPointsOption, Option<string> formatOption)
{
var group = new Command("scope-rule") { Description = "Manage LDAP scope rules" };
var mappingIdOption = new Option<int>("--mapping-id") { Description = "Role mapping ID", Required = true };
var listCmd = new Command("list") { Description = "List scope rules for a mapping" };
listCmd.Add(mappingIdOption);
listCmd.SetAction(async (ParseResult result) =>
{
var mappingId = result.GetValue(mappingIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new ListScopeRulesCommand(mappingId));
});
group.Add(listCmd);
var addMappingIdOption = new Option<int>("--mapping-id") { Description = "Role mapping ID", Required = true };
var siteIdOption = new Option<int>("--site-id") { Description = "Site ID", Required = true };
var addCmd = new Command("add") { Description = "Add a scope rule" };
addCmd.Add(addMappingIdOption);
addCmd.Add(siteIdOption);
addCmd.SetAction(async (ParseResult result) =>
{
var mappingId = result.GetValue(addMappingIdOption);
var siteId = result.GetValue(siteIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new AddScopeRuleCommand(mappingId, siteId));
});
group.Add(addCmd);
var deleteIdOption = new Option<int>("--id") { Description = "Scope rule ID", Required = true };
var deleteCmd = new Command("delete") { Description = "Delete a scope rule" };
deleteCmd.Add(deleteIdOption);
deleteCmd.SetAction(async (ParseResult result) =>
{
var id = result.GetValue(deleteIdOption);
return await CommandHelpers.ExecuteCommandAsync(
result, contactPointsOption, formatOption, new DeleteScopeRuleCommand(id));
});
group.Add(deleteCmd);
return group;
}
}