Files
kanban_cpp/main.cpp
T
egutierrez 98bf278472 chore: auto-commit (8 archivos)
- backend/handlers.go
- data.cpp
- data.h
- main.cpp
- panel_board.cpp
- panel_filters.cpp
- appicon.ico
- backend/kanban_cpp_backend.exe

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 19:38:15 +02:00

115 lines
3.4 KiB
C++

#include <imgui.h>
#include <atomic>
#include <chrono>
#include <cstdio>
#include <cstring>
#include <string>
#include <thread>
#include "app_base.h"
#include "core/panel_menu.h"
#include "core/icons_tabler.h"
#include "core/logger.h"
#include "panels.h"
#include "data.h"
static bool g_show_board = true;
static bool g_show_flows = true;
static bool g_show_filters = true;
static bool g_show_detail = true;
static std::atomic<bool> g_refresh_thread_alive{false};
static std::thread g_refresh_thread;
static void start_refresh_thread() {
g_refresh_thread_alive = true;
g_refresh_thread = std::thread([]() {
kanban::refresh_meta();
kanban::refresh_issues();
kanban::refresh_flows();
kanban::refresh_agent_status();
kanban::start_sse();
int tick = 0;
while (g_refresh_thread_alive) {
// Fast loop (every 3s) for agent status; full refresh every 30s.
std::this_thread::sleep_for(std::chrono::seconds(3));
if (!g_refresh_thread_alive) break;
kanban::refresh_agent_status();
if (++tick >= 10) {
tick = 0;
kanban::refresh_issues();
kanban::refresh_flows();
}
}
kanban::stop_sse();
});
}
static void stop_refresh_thread() {
g_refresh_thread_alive = false;
if (g_refresh_thread.joinable()) g_refresh_thread.join();
}
static void render() {
if (g_show_board) kanban::draw_board();
if (g_show_flows) kanban::draw_flows();
if (g_show_filters) kanban::draw_filters();
if (g_show_detail) kanban::draw_detail();
}
static int run_self_test() {
kanban::State& s = kanban::state();
s.backend_url = "http://127.0.0.1:1";
bool ok_issues = kanban::refresh_issues();
bool ok_flows = kanban::refresh_flows();
if (ok_issues || ok_flows) {
std::fprintf(stderr, "[self-test] expected refresh to fail on unreachable backend\n");
return 1;
}
kanban::Issue dummy;
dummy.status = "pendiente";
dummy.priority = "media";
if (!kanban::passes_filters(dummy)) {
std::fprintf(stderr, "[self-test] empty filters should let issue pass\n");
return 2;
}
s.filters.priorities.insert("alta");
if (kanban::passes_filters(dummy)) {
std::fprintf(stderr, "[self-test] priority filter should reject media when alta required\n");
return 3;
}
std::fprintf(stdout, "[self-test] ok\n");
return 0;
}
int main(int argc, char** argv) {
for (int i = 1; i < argc; ++i) {
if (std::strcmp(argv[i], "--self-test") == 0) {
return run_self_test();
}
if (std::strcmp(argv[i], "--backend") == 0 && i + 1 < argc) {
kanban::state().backend_url = argv[++i];
}
}
static fn_ui::PanelToggle panels[] = {
{ "Board", nullptr, &g_show_board },
{ "Flows", nullptr, &g_show_flows },
{ "Filters", nullptr, &g_show_filters },
{ "Detail", nullptr, &g_show_detail },
};
fn::AppConfig cfg;
cfg.title = "kanban_cpp v2 — dev/issues + dev/flows";
cfg.about = { "kanban_cpp", "0.2.0", "Kanban C++ v2 — gestor de dev/issues y dev/flows del registry" };
cfg.log = { "kanban_cpp.log", 1 };
cfg.panels = panels;
cfg.panel_count = sizeof(panels) / sizeof(panels[0]);
start_refresh_thread();
int rc = fn::run_app(cfg, render);
stop_refresh_thread();
return rc;
}