fix(cli): resolve CLI-014..016 — re-triage update-command contract, doc-surface drift, table-column union

This commit is contained in:
Joseph Doherty
2026-05-17 03:18:16 -04:00
parent 0ba4e49e11
commit f82bcbed7c
6 changed files with 341 additions and 61 deletions

View File

@@ -181,9 +181,25 @@ internal static class CommandHelpers
return;
}
var headers = items[0].ValueKind == JsonValueKind.Object
? items[0].EnumerateObject().Select(p => p.Name).ToArray()
: new[] { "Value" };
// Derive the header set as the union of property names across *every*
// element, in first-seen order. Using only items[0] would silently drop
// columns for any later element with a different shape (CLI-016).
var objectItems = items.Where(i => i.ValueKind == JsonValueKind.Object).ToList();
string[] headers;
if (objectItems.Count > 0)
{
var seen = new List<string>();
var known = new HashSet<string>(StringComparer.Ordinal);
foreach (var item in objectItems)
foreach (var prop in item.EnumerateObject())
if (known.Add(prop.Name))
seen.Add(prop.Name);
headers = seen.ToArray();
}
else
{
headers = new[] { "Value" };
}
var rows = items.Select(item =>
{

View File

@@ -120,16 +120,18 @@ scadalink --url <url> template create --name <string> [--description <string>] [
#### `template update`
Update an existing template's name, description, or parent.
Update an existing template. An update **replaces** the whole entity — every required
field below must be supplied with the value it should have after the update, even if
it is unchanged.
```sh
scadalink --url <url> template update --id <int> [--name <string>] [--description <string>] [--parent-id <int>]
scadalink --url <url> template update --id <int> --name <string> [--description <string>] [--parent-id <int>]
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Template ID |
| `--name` | no | Updated template name |
| `--name` | yes | Template name |
| `--description` | no | Updated description |
| `--parent-id` | no | Updated parent template ID |
@@ -313,16 +315,15 @@ scadalink --url <url> template composition add --template-id <int> --module-temp
#### `template composition delete`
Remove a feature module composition from a template.
Remove a feature module composition from a template, identified by its own composition ID.
```sh
scadalink --url <url> template composition delete --template-id <int> --instance-name <string>
scadalink --url <url> template composition delete --id <int>
```
| Option | Required | Description |
|--------|----------|-------------|
| `--template-id` | yes | Target template ID |
| `--instance-name` | yes | Instance name of the composed module to remove |
| `--id` | yes | Composition ID to remove |
---
@@ -520,17 +521,17 @@ scadalink --url <url> site area create --site-id <int> --name <string> [--parent
#### `site area update`
Update an area's name or parent.
Update an area's name. An update **replaces** the whole entity — the required field
below must be supplied, even if unchanged.
```sh
scadalink --url <url> site area update --id <int> [--name <string>] [--parent-area-id <int>]
scadalink --url <url> site area update --id <int> --name <string>
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Area ID |
| `--name` | no | Updated area name |
| `--parent-area-id` | no | Updated parent area ID |
| `--name` | yes | Area name |
#### `site area delete`
@@ -620,7 +621,7 @@ scadalink --url <url> data-connection list [--site-id <int>]
Create a new data connection belonging to a specific site.
```sh
scadalink --url <url> data-connection create --site-id <int> --name <string> --protocol <string> [--configuration <json>]
scadalink --url <url> data-connection create --site-id <int> --name <string> --protocol <string> [--primary-config <json>] [--backup-config <json>] [--failover-retry-count <int>]
```
| Option | Required | Description |
@@ -628,22 +629,27 @@ scadalink --url <url> data-connection create --site-id <int> --name <string> --p
| `--site-id` | yes | Site ID the connection belongs to |
| `--name` | yes | Connection name |
| `--protocol` | yes | Protocol identifier (e.g. `OpcUa`) |
| `--configuration` | no | Protocol-specific configuration as a JSON string |
| `--primary-config` | no | Primary protocol-specific configuration as a JSON string (alias `--configuration`) |
| `--backup-config` | no | Backup protocol-specific configuration as a JSON string |
| `--failover-retry-count` | no | Retries before failover to the backup configuration (default: `3`) |
#### `data-connection update`
Update a data connection definition.
Update a data connection definition. An update **replaces** the whole entity — every
required field below must be supplied, even if unchanged.
```sh
scadalink --url <url> data-connection update --id <int> [--name <string>] [--protocol <string>] [--configuration <json>]
scadalink --url <url> data-connection update --id <int> --name <string> --protocol <string> [--primary-config <json>] [--backup-config <json>] [--failover-retry-count <int>]
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Data connection ID |
| `--name` | no | Updated connection name |
| `--protocol` | no | Updated protocol identifier |
| `--configuration` | no | Updated protocol-specific configuration as a JSON string |
| `--name` | yes | Connection name |
| `--protocol` | yes | Protocol identifier |
| `--primary-config` | no | Primary protocol-specific configuration as a JSON string (alias `--configuration`) |
| `--backup-config` | no | Backup protocol-specific configuration as a JSON string |
| `--failover-retry-count` | no | Retries before failover to the backup configuration (default: `3`) |
#### `data-connection delete`
@@ -698,18 +704,19 @@ scadalink --url <url> external-system create --name <string> --endpoint-url <url
#### `external-system update`
Update an external system definition.
Update an external system definition. An update **replaces** the whole entity — every
required field below must be supplied, even if unchanged.
```sh
scadalink --url <url> external-system update --id <int> [--name <string>] [--endpoint-url <url>] [--auth-type <string>] [--auth-config <json>]
scadalink --url <url> external-system update --id <int> --name <string> --endpoint-url <url> --auth-type <string> [--auth-config <json>]
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | External system ID |
| `--name` | no | Updated display name |
| `--endpoint-url` | no | Updated base URL |
| `--auth-type` | no | Updated authentication type |
| `--name` | yes | Display name |
| `--endpoint-url` | yes | Base URL |
| `--auth-type` | yes | Authentication type |
| `--auth-config` | no | Updated auth credentials as a JSON string |
#### `external-system delete`
@@ -763,17 +770,18 @@ scadalink --url <url> notification create --name <string> --emails <email1,email
#### `notification update`
Update a notification list's name or recipients.
Update a notification list. An update **replaces** the whole entity — every required
field below must be supplied, even if unchanged.
```sh
scadalink --url <url> notification update --id <int> [--name <string>] [--emails <email1,email2,...>]
scadalink --url <url> notification update --id <int> --name <string> --emails <email1,email2,...>
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Notification list ID |
| `--name` | no | Updated list name |
| `--emails` | no | Updated comma-separated list of recipient email addresses |
| `--name` | yes | List name |
| `--emails` | yes | Comma-separated list of recipient email addresses |
#### `notification delete`
@@ -885,17 +893,18 @@ scadalink --url <url> security role-mapping create --ldap-group <string> --role
#### `security role-mapping update`
Update an LDAP role mapping.
Update an LDAP role mapping. An update **replaces** the whole entity — every required
field below must be supplied, even if unchanged.
```sh
scadalink --url <url> security role-mapping update --id <int> [--ldap-group <string>] [--role <string>]
scadalink --url <url> security role-mapping update --id <int> --ldap-group <string> --role <string>
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Mapping ID |
| `--ldap-group` | no | Updated LDAP group distinguished name or CN |
| `--role` | no | Updated ScadaLink role |
| `--ldap-group` | yes | LDAP group distinguished name or CN |
| `--role` | yes | ScadaLink role |
#### `security role-mapping delete`
@@ -1099,17 +1108,20 @@ scadalink --url <url> shared-script create --name <string> --code <string>
#### `shared-script update`
Update a shared script's name or code.
Update a shared script. An update **replaces** the whole entity — every required field
below must be supplied, even if unchanged.
```sh
scadalink --url <url> shared-script update --id <int> [--name <string>] [--code <string>]
scadalink --url <url> shared-script update --id <int> --name <string> --code <string> [--parameters <json>] [--return-def <json>]
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Shared script ID |
| `--name` | no | Updated script name |
| `--code` | no | Updated script source code (or `@filepath`) |
| `--name` | yes | Shared script name |
| `--code` | yes | Script source code |
| `--parameters` | no | Parameter definitions JSON |
| `--return-def` | no | Return type definition JSON |
#### `shared-script delete`
@@ -1163,18 +1175,18 @@ scadalink --url <url> db-connection create --name <string> --connection-string <
#### `db-connection update`
Update a database connection definition.
Update a database connection definition. An update **replaces** the whole entity —
every required field below must be supplied, even if unchanged.
```sh
scadalink --url <url> db-connection update --id <int> [--name <string>] [--connection-string <string>] [--provider <string>]
scadalink --url <url> db-connection update --id <int> --name <string> --connection-string <string>
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | Database connection ID |
| `--name` | no | Updated connection name |
| `--connection-string` | no | Updated connection string |
| `--provider` | no | Updated database provider |
| `--name` | yes | Connection name |
| `--connection-string` | yes | Database connection string |
#### `db-connection delete`
@@ -1228,18 +1240,20 @@ scadalink --url <url> api-method create --name <string> --code <string> [--descr
#### `api-method update`
Update an inbound API method.
Update an inbound API method. An update **replaces** the whole entity — every required
field below must be supplied, even if unchanged.
```sh
scadalink --url <url> api-method update --id <int> [--name <string>] [--code <string>] [--description <string>]
scadalink --url <url> api-method update --id <int> --script <string> [--timeout <int>] [--parameters <json>] [--return-def <json>]
```
| Option | Required | Description |
|--------|----------|-------------|
| `--id` | yes | API method ID |
| `--name` | no | Updated method name |
| `--code` | no | Updated script source code (or `@filepath`) |
| `--description` | no | Updated description |
| Option | Required | Default | Description |
|--------|----------|---------|-------------|
| `--id` | yes | — | API method ID |
| `--script` | yes | — | Script source code implementing the method |
| `--timeout` | no | `30` | Timeout in seconds |
| `--parameters` | no | — | Parameter definitions JSON |
| `--return-def` | no | — | Return type definition JSON |
Script changes take effect immediately — the updated code is recompiled in-memory on the active central node. No restart is required.