diff --git a/README.md b/README.md index ccb96ea0..55cd6bc7 100644 --- a/README.md +++ b/README.md @@ -213,9 +213,25 @@ broadcast selections, expose variables to tile queries, or do both: } ``` -Run `dashboard validate` before create or update to check the same dashboard body without saving it. -`dashboard update --config-file dashboard.json` is a full PUT replacement: -include every tile, filter, container, tag, and saved query value that should remain. +`dashboard validate` checks a create body without saving it; it does not accept or validate an update body. +Dashboard updates use a separate full PUT body. Start from the complete current dashboard, preserve the +`id` of every existing filter, and include every tile, filter, container, tag, and saved query value that +should remain. For example, an existing filter entry in `dashboard-update.json` must retain its identity: + +```json +{ + "id": "", + "name": "Service", + "expression": "ServiceName", + "sourceId": "", + "type": "QUERY_EXPRESSION" +} +``` + +```bash +clickhousectl cloud clickstack dashboard update \ + --config-file dashboard-update.json --org-id +``` Create a notification destination first, then reference its ID from an alert. For example, `webhook.json` can contain a complete generic webhook body: diff --git a/crates/clickhousectl/src/cloud/clickstack.rs b/crates/clickhousectl/src/cloud/clickstack.rs index 62f6d1b5..986b7fdf 100644 --- a/crates/clickhousectl/src/cloud/clickstack.rs +++ b/crates/clickhousectl/src/cloud/clickstack.rs @@ -236,13 +236,14 @@ pub enum DashboardCommands { #[command(after_help = "\ CONTEXT FOR AGENTS: This is a full PUT replacement; include every required and desired field. + Every existing filter must retain its `id` in the request body. Serialize edits to one dashboard; concurrent updates can overwrite each other.")] Update { /// Service ID (from `cloud service list`) service_id: String, /// Dashboard ID (from `cloud clickstack dashboard list`) dashboard_id: String, - /// Complete JSON request body path, or `-` for stdin + /// Complete update JSON body path, or `-` for stdin #[arg(long, value_name = "PATH|-", required = true)] config_file: String, /// Organization ID (auto-detected only if you have one org) @@ -259,15 +260,16 @@ CONTEXT FOR AGENTS: #[arg(long)] org_id: Option, }, - /// Validate a ClickStack dashboard without saving it + /// Validate a dashboard create body without saving it #[command(after_help = "\ CONTEXT FOR AGENTS: + Accepts the create schema only; it does not validate update bodies. Validation never persists the dashboard. Uses API key authentication under the CLI's write-command policy.")] Validate { /// Service ID (from `cloud service list`) service_id: String, - /// JSON request body path, or `-` for stdin + /// Dashboard create JSON body path, or `-` for stdin #[arg(long, value_name = "PATH|-", required = true)] config_file: String, /// Organization ID (auto-detected only if you have one org)