#include #include #include #include #include #include #include #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 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::start_sse(); while (g_refresh_thread_alive) { std::this_thread::sleep_for(std::chrono::seconds(30)); if (!g_refresh_thread_alive) break; 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; }