feat(common): add DeleteItems API and CLI command
This commit is contained in:
parent
b26a04e392
commit
a2a3dbc771
|
|
@ -41,6 +41,7 @@ Deferred manual/runtime verification (implemented after 2026-02-20 while user un
|
|||
- `RunAction`
|
||||
- `CreateItems`
|
||||
- `UpdateItems`
|
||||
- `DeleteItems`
|
||||
|
||||
## KiCad v10 RC1.1 API Completion Matrix
|
||||
|
||||
|
|
@ -61,11 +62,11 @@ Legend:
|
|||
| Section | Proto Commands | Implemented | Coverage |
|
||||
| --- | ---: | ---: | ---: |
|
||||
| Common (base) | 6 | 6 | 100% |
|
||||
| Common editor/document | 23 | 21 | 91% |
|
||||
| Common editor/document | 23 | 22 | 96% |
|
||||
| Project manager | 5 | 3 | 60% |
|
||||
| Board editor (PCB) | 22 | 20 | 91% |
|
||||
| Schematic editor (dedicated proto commands) | 0 | 0 | n/a |
|
||||
| **Total** | **56** | **50** | **89%** |
|
||||
| **Total** | **56** | **51** | **91%** |
|
||||
|
||||
### Common (base)
|
||||
|
||||
|
|
@ -94,7 +95,7 @@ Legend:
|
|||
| `GetItems` | Implemented | `KiCadClient::get_items_raw_by_type_codes`, `KiCadClient::get_items_by_type_codes`, `KiCadClient::get_items_details_by_type_codes`, `KiCadClient::get_all_pcb_items_raw`, `KiCadClient::get_all_pcb_items`, `KiCadClient::get_all_pcb_items_details`, `KiCadClient::get_pad_netlist` |
|
||||
| `GetItemsById` | Implemented | `KiCadClient::get_items_by_id_raw`, `KiCadClient::get_items_by_id`, `KiCadClient::get_items_by_id_details` |
|
||||
| `UpdateItems` | Implemented | `KiCadClient::update_items_raw`, `KiCadClient::update_items` |
|
||||
| `DeleteItems` | Not yet | - |
|
||||
| `DeleteItems` | Implemented | `KiCadClient::delete_items_raw`, `KiCadClient::delete_items` |
|
||||
| `GetBoundingBox` | Implemented | `KiCadClient::get_item_bounding_boxes` |
|
||||
| `GetSelection` | Implemented | `KiCadClient::get_selection_raw`, `KiCadClient::get_selection`, `KiCadClient::get_selection_summary`, `KiCadClient::get_selection_details` |
|
||||
| `AddToSelection` | Implemented | `KiCadClient::add_to_selection_raw`, `KiCadClient::add_to_selection` |
|
||||
|
|
|
|||
|
|
@ -199,6 +199,12 @@ Update raw Any item payload(s):
|
|||
cargo run --bin kicad-ipc-cli -- update-items --item type.googleapis.com/kiapi.board.types.Text=<hex_payload>
|
||||
```
|
||||
|
||||
Delete items by ID:
|
||||
|
||||
```bash
|
||||
cargo run --bin kicad-ipc-cli -- delete-items --id <uuid> --id <uuid>
|
||||
```
|
||||
|
||||
Show summary of current PCB selection by item type:
|
||||
|
||||
```bash
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ const CMD_BEGIN_COMMIT: &str = "kiapi.common.commands.BeginCommit";
|
|||
const CMD_END_COMMIT: &str = "kiapi.common.commands.EndCommit";
|
||||
const CMD_CREATE_ITEMS: &str = "kiapi.common.commands.CreateItems";
|
||||
const CMD_UPDATE_ITEMS: &str = "kiapi.common.commands.UpdateItems";
|
||||
const CMD_DELETE_ITEMS: &str = "kiapi.common.commands.DeleteItems";
|
||||
const CMD_GET_ITEMS: &str = "kiapi.common.commands.GetItems";
|
||||
const CMD_GET_ITEMS_BY_ID: &str = "kiapi.common.commands.GetItemsById";
|
||||
const CMD_GET_BOUNDING_BOX: &str = "kiapi.common.commands.GetBoundingBox";
|
||||
|
|
@ -118,6 +119,7 @@ const RES_BEGIN_COMMIT_RESPONSE: &str = "kiapi.common.commands.BeginCommitRespon
|
|||
const RES_END_COMMIT_RESPONSE: &str = "kiapi.common.commands.EndCommitResponse";
|
||||
const RES_CREATE_ITEMS_RESPONSE: &str = "kiapi.common.commands.CreateItemsResponse";
|
||||
const RES_UPDATE_ITEMS_RESPONSE: &str = "kiapi.common.commands.UpdateItemsResponse";
|
||||
const RES_DELETE_ITEMS_RESPONSE: &str = "kiapi.common.commands.DeleteItemsResponse";
|
||||
const RES_GET_ITEMS_RESPONSE: &str = "kiapi.common.commands.GetItemsResponse";
|
||||
const RES_GET_BOUNDING_BOX_RESPONSE: &str = "kiapi.common.commands.GetBoundingBoxResponse";
|
||||
const RES_HIT_TEST_RESPONSE: &str = "kiapi.common.commands.HitTestResponse";
|
||||
|
|
@ -695,6 +697,44 @@ impl KiCadClient {
|
|||
.collect()
|
||||
}
|
||||
|
||||
pub async fn delete_items_raw(
|
||||
&self,
|
||||
item_ids: Vec<String>,
|
||||
) -> Result<prost_types::Any, KiCadError> {
|
||||
let command = common_commands::DeleteItems {
|
||||
header: Some(self.current_board_item_header().await?),
|
||||
item_ids: item_ids
|
||||
.into_iter()
|
||||
.map(|value| common_types::Kiid { value })
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let response = self
|
||||
.send_command(envelope::pack_any(&command, CMD_DELETE_ITEMS))
|
||||
.await?;
|
||||
response_payload_as_any(response, RES_DELETE_ITEMS_RESPONSE)
|
||||
}
|
||||
|
||||
pub async fn delete_items(&self, item_ids: Vec<String>) -> Result<Vec<String>, KiCadError> {
|
||||
let payload = self.delete_items_raw(item_ids).await?;
|
||||
let response: common_commands::DeleteItemsResponse =
|
||||
decode_any(&payload, RES_DELETE_ITEMS_RESPONSE)?;
|
||||
ensure_item_request_ok(response.status)?;
|
||||
|
||||
response
|
||||
.deleted_items
|
||||
.into_iter()
|
||||
.map(|row| {
|
||||
ensure_item_deletion_status_ok(row.status)?;
|
||||
row.id
|
||||
.map(|id| id.value)
|
||||
.ok_or_else(|| KiCadError::InvalidResponse {
|
||||
reason: "DeleteItemsResponse missing deleted item id".to_string(),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub async fn get_nets(&self) -> Result<Vec<BoardNet>, KiCadError> {
|
||||
let board = self.current_board_document_proto().await?;
|
||||
let command = board_commands::GetNets {
|
||||
|
|
@ -2160,6 +2200,19 @@ fn ensure_item_status_ok(status: Option<common_commands::ItemStatus>) -> Result<
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn ensure_item_deletion_status_ok(status: i32) -> Result<(), KiCadError> {
|
||||
let code = common_commands::ItemDeletionStatus::try_from(status)
|
||||
.unwrap_or(common_commands::ItemDeletionStatus::IdsUnknown);
|
||||
|
||||
if code != common_commands::ItemDeletionStatus::IdsOk {
|
||||
return Err(KiCadError::ItemStatus {
|
||||
code: code.as_str_name().to_string(),
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn map_item_bounding_boxes(
|
||||
item_ids: Vec<common_types::Kiid>,
|
||||
boxes: Vec<common_types::Box2>,
|
||||
|
|
@ -3281,13 +3334,13 @@ fn default_client_name() -> String {
|
|||
mod tests {
|
||||
use super::{
|
||||
any_to_pretty_debug, board_editor_appearance_settings_to_proto, commit_action_to_proto,
|
||||
drc_severity_to_proto, ensure_item_request_ok, ensure_item_status_ok, layer_to_model,
|
||||
map_commit_session, map_hit_test_result, map_item_bounding_boxes, map_polygon_with_holes,
|
||||
map_run_action_status, model_document_to_proto, normalize_socket_uri,
|
||||
pad_netlist_from_footprint_items, response_payload_as_any, select_single_board_document,
|
||||
select_single_project_path, selection_item_detail, summarize_item_details,
|
||||
summarize_selection, text_horizontal_alignment_to_proto, text_spec_to_proto,
|
||||
PCB_OBJECT_TYPES,
|
||||
drc_severity_to_proto, ensure_item_deletion_status_ok, ensure_item_request_ok,
|
||||
ensure_item_status_ok, layer_to_model, map_commit_session, map_hit_test_result,
|
||||
map_item_bounding_boxes, map_polygon_with_holes, map_run_action_status,
|
||||
model_document_to_proto, normalize_socket_uri, pad_netlist_from_footprint_items,
|
||||
response_payload_as_any, select_single_board_document, select_single_project_path,
|
||||
selection_item_detail, summarize_item_details, summarize_selection,
|
||||
text_horizontal_alignment_to_proto, text_spec_to_proto, PCB_OBJECT_TYPES,
|
||||
};
|
||||
use crate::error::KiCadError;
|
||||
use crate::model::common::{
|
||||
|
|
@ -3713,6 +3766,23 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn ensure_item_deletion_status_ok_accepts_ok_and_rejects_non_ok() {
|
||||
assert!(ensure_item_deletion_status_ok(
|
||||
crate::proto::kiapi::common::commands::ItemDeletionStatus::IdsOk as i32
|
||||
)
|
||||
.is_ok());
|
||||
|
||||
let err = ensure_item_deletion_status_ok(
|
||||
crate::proto::kiapi::common::commands::ItemDeletionStatus::IdsNonexistent as i32,
|
||||
)
|
||||
.expect_err("non-OK item deletion status should fail");
|
||||
match err {
|
||||
KiCadError::ItemStatus { code } => assert_eq!(code, "IDS_NONEXISTENT"),
|
||||
_ => panic!("expected item status error"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn summarize_item_details_reports_unknown_payload_as_unparsed() {
|
||||
let items = vec![prost_types::Any {
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue