From e4d9a72a3c2919a6097a2c96e650d7ef36509f48 Mon Sep 17 00:00:00 2001 From: Bill Date: Tue, 17 Feb 2026 22:09:48 -0700 Subject: [PATCH] Step 655: swarm status panel model --- editor/CMakeLists.txt | 9 ++++++ editor/src/SwarmStatusPanelModel.h | 46 ++++++++++++++++++++++++++++++ editor/tests/step655_test.cpp | 27 ++++++++++++++++++ progress.md | 24 ++++++++++++++++ 4 files changed, 106 insertions(+) create mode 100644 editor/src/SwarmStatusPanelModel.h create mode 100644 editor/tests/step655_test.cpp diff --git a/editor/CMakeLists.txt b/editor/CMakeLists.txt index 72b2a79..2569382 100644 --- a/editor/CMakeLists.txt +++ b/editor/CMakeLists.txt @@ -4774,4 +4774,13 @@ target_link_libraries(step654_test PRIVATE tree_sitter_javascript tree_sitter_typescript tree_sitter_java tree_sitter_rust tree_sitter_go) +add_executable(step655_test tests/step655_test.cpp) +target_include_directories(step655_test PRIVATE src) +target_link_libraries(step655_test PRIVATE + nlohmann_json::nlohmann_json + unofficial::tree-sitter::tree-sitter + tree_sitter_python tree_sitter_cpp tree_sitter_elisp + tree_sitter_javascript tree_sitter_typescript + tree_sitter_java tree_sitter_rust tree_sitter_go) + # Step 12: Dear ImGui shell scaffolding created (main.cpp exists but not built due to dependencies) diff --git a/editor/src/SwarmStatusPanelModel.h b/editor/src/SwarmStatusPanelModel.h new file mode 100644 index 0000000..b95dd8b --- /dev/null +++ b/editor/src/SwarmStatusPanelModel.h @@ -0,0 +1,46 @@ +#pragma once +// Step 655: Job status subscriber panel model + +#include +#include + +enum class SwarmJobState { Pending, Running, Completed, Failed }; + +struct SwarmJobStatusItem { + std::string jobId; + std::string node; + int runningSeconds = 0; + SwarmJobState state = SwarmJobState::Pending; +}; + +struct SwarmStatusSummary { + int pending = 0; + int running = 0; + int completed = 0; + int failed = 0; +}; + +class SwarmStatusPanelModel { +public: + static SwarmStatusSummary summarize(const std::vector& items) { + SwarmStatusSummary s; + for (const auto& i : items) { + if (i.state == SwarmJobState::Pending) ++s.pending; + else if (i.state == SwarmJobState::Running) ++s.running; + else if (i.state == SwarmJobState::Completed) ++s.completed; + else ++s.failed; + } + return s; + } + + static std::string label(const SwarmJobStatusItem& item) { + return item.jobId + "@" + item.node; + } + + static std::string stateText(SwarmJobState state) { + if (state == SwarmJobState::Pending) return "pending"; + if (state == SwarmJobState::Running) return "running"; + if (state == SwarmJobState::Completed) return "completed"; + return "failed"; + } +}; diff --git a/editor/tests/step655_test.cpp b/editor/tests/step655_test.cpp new file mode 100644 index 0000000..59c511a --- /dev/null +++ b/editor/tests/step655_test.cpp @@ -0,0 +1,27 @@ +// Step 655: Job status subscriber panel (12 tests) + +#include "SwarmStatusPanelModel.h" +#include +static int p=0,f=0; +#define T(n) { std::cout<<" "<<#n<<"... "; } +#define P() { std::cout<<"PASS\n"; ++p; } +#define F(m) { std::cout<<"FAIL: "< sample(){ +return {{"j1","nodeA",0,SwarmJobState::Pending},{"j2","nodeB",12,SwarmJobState::Running},{"j3","nodeC",30,SwarmJobState::Completed},{"j4","nodeD",5,SwarmJobState::Failed}};} + +void t1(){T(summary_counts_pending);auto s=SwarmStatusPanelModel::summarize(sample());C(s.pending==1,"pending");P();} +void t2(){T(summary_counts_running);auto s=SwarmStatusPanelModel::summarize(sample());C(s.running==1,"running");P();} +void t3(){T(summary_counts_completed);auto s=SwarmStatusPanelModel::summarize(sample());C(s.completed==1,"completed");P();} +void t4(){T(summary_counts_failed);auto s=SwarmStatusPanelModel::summarize(sample());C(s.failed==1,"failed");P();} +void t5(){T(label_combines_job_and_node);C(SwarmStatusPanelModel::label(sample()[0])=="j1@nodeA","label");P();} +void t6(){T(state_text_pending);C(SwarmStatusPanelModel::stateText(SwarmJobState::Pending)=="pending","text");P();} +void t7(){T(state_text_running);C(SwarmStatusPanelModel::stateText(SwarmJobState::Running)=="running","text");P();} +void t8(){T(state_text_completed);C(SwarmStatusPanelModel::stateText(SwarmJobState::Completed)=="completed","text");P();} +void t9(){T(state_text_failed);C(SwarmStatusPanelModel::stateText(SwarmJobState::Failed)=="failed","text");P();} +void t10(){T(empty_summary_all_zero);auto s=SwarmStatusPanelModel::summarize({});C(s.pending==0&&s.running==0&&s.completed==0&&s.failed==0,"empty");P();} +void t11(){T(running_duration_preserved);auto i=sample()[1];C(i.runningSeconds==12,"duration");P();} +void t12(){T(multi_pending_counts_correctly);auto v=sample();v.push_back({"j5","nodeE",0,SwarmJobState::Pending});auto s=SwarmStatusPanelModel::summarize(v);C(s.pending==2,"multi");P();} + +int main(){std::cout<<"Step 655: Swarm status panel\n";t1();t2();t3();t4();t5();t6();t7();t8();t9();t10();t11();t12();std::cout<<"\nResults: "<