feat(layout): supporte la création de layouts plugins (customPluginLayout)
Étend le flux de création de layout backend (DTO, usecases, store) et le frontend (sélecteur, adaptateurs, LayoutTabs/LayoutGrid) pour permettre d'ouvrir un layout déclaré par un plugin installé (ex. Android Health), sans passer par le message bloquant "extension backend pas encore livrée". Ticket #141 — QA vert. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@ -10,8 +10,10 @@ use app_tauri_lib::dto::{
|
||||
};
|
||||
use application::{
|
||||
CreateLayoutOutput, DeleteLayoutOutput, LayoutInfo, LayoutKind, ListLayoutsOutput,
|
||||
PluginLayoutOrigin,
|
||||
};
|
||||
use domain::ids::{AgentId, LayoutId, NodeId};
|
||||
use domain::{PluginId, PluginLayoutType};
|
||||
use serde_json::json;
|
||||
use uuid::Uuid;
|
||||
|
||||
@ -55,6 +57,24 @@ fn layout_info_dto_git_graph_kind() {
|
||||
assert_eq!(v["kind"], "gitGraph");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn layout_info_dto_plugin_kind() {
|
||||
let info = LayoutInfo {
|
||||
id: lid(3),
|
||||
name: "Android Health".to_owned(),
|
||||
kind: LayoutKind::Plugin {
|
||||
plugin_origin: PluginLayoutOrigin {
|
||||
plugin_id: PluginId::new("dev.idea.android-plugin").unwrap(),
|
||||
layout_type: PluginLayoutType::new("idea-android.health").unwrap(),
|
||||
},
|
||||
state: json!({}),
|
||||
},
|
||||
};
|
||||
let dto = LayoutInfoDto::from(info);
|
||||
let v = serde_json::to_value(&dto).unwrap();
|
||||
assert_eq!(v["kind"], "plugin");
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ListLayoutsDto
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -138,6 +158,43 @@ fn create_layout_request_with_git_graph_kind() {
|
||||
assert_eq!(kind, application::LayoutKind::GitGraph);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_layout_request_with_plugin_kind() {
|
||||
let project_id = Uuid::from_u128(13).to_string();
|
||||
let raw = json!({
|
||||
"projectId": project_id,
|
||||
"name": "Android Health",
|
||||
"kind": "plugin",
|
||||
"pluginOrigin": {
|
||||
"pluginId": "dev.idea.android-plugin",
|
||||
"layoutType": "idea-android.health"
|
||||
},
|
||||
"state": { "deviceId": "pixel-8" }
|
||||
});
|
||||
let dto: CreateLayoutRequestDto = serde_json::from_value(raw).unwrap();
|
||||
let kind = dto.parse_kind().unwrap();
|
||||
match kind {
|
||||
application::LayoutKind::Plugin {
|
||||
plugin_origin,
|
||||
state,
|
||||
} => {
|
||||
assert_eq!(plugin_origin.plugin_id.as_str(), "dev.idea.android-plugin");
|
||||
assert_eq!(plugin_origin.layout_type.as_str(), "idea-android.health");
|
||||
assert_eq!(state["deviceId"], "pixel-8");
|
||||
}
|
||||
_ => panic!("expected plugin layout kind"),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_layout_request_plugin_kind_requires_origin() {
|
||||
let project_id = Uuid::from_u128(14).to_string();
|
||||
let raw = json!({ "projectId": project_id, "name": "Android Health", "kind": "plugin" });
|
||||
let dto: CreateLayoutRequestDto = serde_json::from_value(raw).unwrap();
|
||||
let err = dto.parse_kind().unwrap_err();
|
||||
assert_eq!(err.code, "INVALID");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn create_layout_request_unknown_kind_is_invalid() {
|
||||
let project_id = Uuid::from_u128(12).to_string();
|
||||
@ -260,6 +317,30 @@ fn set_cell_agent_op_deserialises_with_absent_agent_defaults_to_none() {
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// setPluginLayoutState operation deserialisation (#141)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
#[test]
|
||||
fn set_plugin_layout_state_op_deserialises_opaque_state() {
|
||||
let target = nid(3);
|
||||
let raw = json!({
|
||||
"type": "setPluginLayoutState",
|
||||
"target": target.to_string(),
|
||||
"state": { "deviceId": "pixel-8", "healthy": true }
|
||||
});
|
||||
let dto: LayoutOperationDto = serde_json::from_value(raw).unwrap();
|
||||
let op = dto.into_operation().unwrap();
|
||||
match op {
|
||||
application::LayoutOperation::SetPluginLayoutState { target: t, state } => {
|
||||
assert_eq!(t, target);
|
||||
assert_eq!(state["deviceId"], "pixel-8");
|
||||
assert_eq!(state["healthy"], true);
|
||||
}
|
||||
_ => panic!("expected SetPluginLayoutState"),
|
||||
}
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// setCellConversation operation deserialisation (T4b)
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user