分层重构

This commit is contained in:
2026-08-08 11:14:50 +08:00
parent 6ac872b9b7
commit 2155ff0e17
25 changed files with 2233 additions and 620 deletions
+120 -56
View File
@@ -1,33 +1,91 @@
#include "example_descriptors.hpp"
#include <cassert>
#include <string>
#include <string_view>
#include <vector>
namespace {
using Json = adminive::example::Json;
const Json* find_named_node(const Json& value, std::string_view name) {
if(value.is_object()) {
if(value.contains("name") && value.at("name").is_string() && value.at("name").get<std::string>() == name) {
return &value;
}
for(const auto& [key, child] : value.items()) {
static_cast<void>(key);
if(const Json* result = find_named_node(child, name)) {
return result;
}
}
} else if(value.is_array()) {
for(const auto& child : value) {
if(const Json* result = find_named_node(child, name)) {
return result;
}
}
}
return nullptr;
}
const Json* find_titled_node(const Json& value, std::string_view title) {
if(value.is_object()) {
if(value.contains("title") && value.at("title").is_string() && value.at("title").get<std::string>() == title) {
return &value;
}
for(const auto& [key, child] : value.items()) {
static_cast<void>(key);
if(const Json* result = find_titled_node(child, title)) {
return result;
}
}
} else if(value.is_array()) {
for(const auto& child : value) {
if(const Json* result = find_titled_node(child, title)) {
return result;
}
}
}
return nullptr;
}
}
int main() {
using adminive::example::Alert_Config;
using adminive::example::Radio_Item_Status;
using adminive::example::Radio_Mode;
using adminive::example::Radio_Service_Config;
using adminive::example::Radio_State;
using Json = adminive::example::Json;
Radio_State state;
const auto descriptor = adminive::to_descriptor_json<Json, Radio_State>();
assert(descriptor.at("protocol") == "adminive.resource");
assert(descriptor.at("protocol_version") == 5);
assert(descriptor.at("name") == "radio_state");
assert(descriptor.at("fields").size() == 5);
assert(descriptor.at("fields").at(0).at("name") == "mode");
assert(descriptor.at("fields").at(0).at("label") == "运行模式");
assert(descriptor.at("fields").at(0).at("list_label") == "模式");
assert(descriptor.at("fields").at(0).at("value_type") == "enum");
assert(descriptor.at("fields").at(0).at("options").size() == 4);
assert(descriptor.at("fields").at(0).at("options").at(0).at("value") == "receive");
assert(descriptor.at("fields").at(0).at("options").at(2).at("value") == "duplex");
assert(descriptor.at("fields").at(0).at("order") == 5);
assert(descriptor.at("fields").at(0).at("sortable") == true);
assert(descriptor.at("fields").at(1).at("name") == "port");
assert(descriptor.at("fields").at(1).at("list_label") == "监听端口");
assert(descriptor.at("fields").at(1).at("minimum") == 1);
assert(descriptor.at("fields").at(1).at("maximum") == 65535);
assert(descriptor.at("fields").at(2).at("name") == "buffer_count");
const auto& mode_field = descriptor.at("fields").at(0);
assert(mode_field.at("name") == "mode");
assert(mode_field.at("presentation").at("label") == "运行模式");
assert(mode_field.at("value_type") == "enum");
assert(mode_field.at("presentation").at("options").size() == 4);
assert(mode_field.at("presentation").at("options").at(0).at("value") == "receive");
assert(mode_field.at("presentation").at("options").at(2).at("value") == "duplex");
const auto& port_field = descriptor.at("fields").at(1);
assert(port_field.at("name") == "port");
assert(port_field.at("presentation").at("label") == "监听端口");
assert(port_field.at("minimum") == 1);
assert(port_field.at("maximum") == 65535);
assert(descriptor.at("fields").at(2).at("multiple_of") == 2);
assert(!descriptor.contains("list"));
const auto table_view = adminive::describe_table_view<Radio_State>();
assert(table_view.columns.size() == 5);
assert(table_view.columns.at(0).field == "mode");
assert(table_view.columns.at(0).label == "模式");
assert(table_view.columns.at(0).sortable);
assert(table_view.columns.at(0).filterable);
assert(table_view.columns.at(2).field == "port");
assert(table_view.columns.at(2).searchable);
assert(table_view.default_order_by == "buffer_count");
const auto table_view_json = adminive::to_view_json<Json, Radio_State>(table_view);
assert(table_view_json.at("protocol") == "adminive.view");
assert(table_view_json.at("kind") == "table");
assert(table_view_json.at("columns").at(0).at("field") == "mode");
assert(table_view_json.at("columns").at(0).at("filterable") == true);
const auto initial = adminive::to_json<Json>(state);
assert(initial.at("mode") == "receive");
assert(initial.at("port") == 9999);
@@ -57,29 +115,27 @@ int main() {
assert(!result.success);
assert(result.field_errors.contains("mode"));
assert(result.field_errors.contains("buffer_count"));
const auto form = adminive::to_amis_form_schema<Json>(state, "/admin/radio_state", "Confirm Changes");
const auto form_view = adminive::edit_form<Radio_State>().submit("Confirm Changes");
const auto form = adminive::to_amis_form_schema<Json>(state, form_view, "/admin/radio_state");
assert(form.at("type") == "form");
assert(form.at("body").size() == 5);
assert(form.at("body").at(0).at("type") == "select");
assert(form.at("body").at(0).at("options").size() == 4);
assert(form.at("body").at(1).at("type") == "input-number");
assert(form.at("body").at(2).at("step") == 2);
assert(form.at("actions").size() == 2);
assert(form.at("actions").at(0).at("type") == "reset");
assert(form.at("actions").at(1).at("type") == "submit");
assert(form.at("actions").at(1).at("label") == "Confirm Changes");
const auto crud = adminive::to_amis_crud_schema<Json, Radio_State>("/admin/radio_states");
const auto crud = adminive::to_amis_table_schema<Json, Radio_State>("/admin/radio_states", table_view);
assert(crud.at("type") == "page");
assert(crud.at("body").at("type") == "crud");
assert(crud.at("body").at("columns").size() == 7);
assert(crud.at("body").at("columns").at(1).at("name") == "mode");
assert(crud.at("body").at("columns").at(1).at("type") == "mapping");
assert(crud.at("body").at("columns").at(1).at("map").at("duplex") == "双工");
assert(crud.at("body").at("columns").at(2).at("name") == "buffer_count");
assert(crud.at("body").at("columns").at(3).at("name") == "port");
assert(!crud.at("body").contains("interval"));
const auto& create_form = crud.at("body").at("headerToolbar").at(2).at("dialog").at("body");
assert(create_form.at("actions").at(1).at("type") == "submit");
const auto& crud_body = crud.at("body").at(0);
assert(crud_body.at("type") == "crud");
assert(crud_body.at("columns").size() == 7);
assert(crud_body.at("columns").at(1).at("name") == "mode");
assert(crud_body.at("columns").at(1).at("type") == "mapping");
assert(crud_body.at("columns").at(1).at("map").at("duplex") == "双工");
assert(crud_body.at("columns").at(1).at("filterable") == true);
assert(crud_body.at("columns").at(3).at("name") == "port");
assert(crud_body.at("columns").at(3).at("searchable") == true);
const auto& create_form = crud_body.at("headerToolbar").at(2).at("dialog").at("body");
assert(create_form.at("actions").at(1).at("label") == "新增");
const auto status_descriptor = adminive::to_status_descriptor_json<Json, Radio_Item_Status>();
assert(status_descriptor.at("protocol") == "adminive.status");
@@ -94,7 +150,7 @@ int main() {
assert(first_status.at("refresh_sequence").at("value") == 1);
assert(second_status.at("refresh_sequence").at("value") == 2);
const auto overview_descriptor = adminive::to_status_descriptor_json<Json, adminive::example::Server_Status>();
const auto status_crud = adminive::to_amis_crud_status_schema<Json, Radio_State>("/admin/radio_states", "/admin/status", overview_descriptor, 2000, &status_descriptor);
const auto status_crud = adminive::to_amis_table_schema<Json, Radio_State>("/admin/radio_states", table_view, &status_descriptor, 2000, &overview_descriptor, "/admin/status", 2000);
assert(status_crud.at("body").is_array());
assert(status_crud.at("body").at(0).at("type") == "service");
assert(status_crud.at("body").at(1).at("columns").size() == 8);
@@ -117,38 +173,46 @@ int main() {
assert(service_descriptor.at("fields").at(3).at("value_type") == "number");
assert(service_descriptor.at("fields").at(4).at("value_type") == "object");
assert(service_descriptor.at("fields").at(4).at("children").size() == 3);
assert(service_descriptor.at("fields").at(5).at("visible_on") == "${$self.mode == 'duplex'}");
assert(service_descriptor.at("fields").at(6).at("children").at(1).at("widget") == "input-date");
assert(service_descriptor.at("fields").at(6).at("children").at(2).at("widget") == "input-color");
const auto service_form = adminive::to_amis_form_schema<Json>(service_config, "/admin/config/radio/data", "Confirm Changes");
assert(service_form.at("body").at(0).at("type") == "input-text");
assert(service_form.at("body").at(1).at("type") == "select");
assert(service_form.at("body").at(2).at("type") == "input-number");
assert(service_form.at("body").at(3).at("type") == "input-number");
assert(service_form.at("body").at(4).at("type") == "fieldset");
assert(service_form.at("body").at(4).at("body").at(1).at("name") == "primary_endpoint.host");
assert(service_form.at("body").at(5).at("visibleOn") == "${mode == 'duplex'}");
assert(service_form.at("body").at(6).at("body").at(1).at("type") == "input-date");
assert(service_form.at("body").at(6).at("body").at(1).at("valueFormat") == "YYYY-MM-DD");
assert(service_form.at("body").at(6).at("body").at(2).at("type") == "input-color");
assert(service_form.at("actions").at(1).at("type") == "submit");
assert(service_descriptor.at("fields").at(5).at("presentation").at("visible_on") == "${$self.mode == 'duplex'}");
assert(service_descriptor.at("fields").at(6).at("children").at(1).at("presentation").at("control") == "date");
assert(service_descriptor.at("fields").at(6).at("children").at(2).at("presentation").at("control") == "color");
const auto service_view = adminive::describe_edit_view<Radio_Service_Config>();
const auto service_view_json = adminive::to_view_json<Json, Radio_Service_Config>(service_view);
assert(service_view_json.at("body").at("kind") == "tabs");
assert(service_view_json.at("body").at("children").size() == 3);
const auto service_form = adminive::to_amis_form_schema<Json>(service_config, service_view, "/admin/config/radio/data");
assert(service_form.at("body").at(0).at("type") == "tabs");
const Json* profile_control = find_named_node(service_form, "profile_name");
const Json* mode_control = find_named_node(service_form, "mode");
const Json* worker_control = find_named_node(service_form, "worker_count");
const Json* date_control = find_named_node(service_form, "appearance.effective_date");
const Json* color_control = find_named_node(service_form, "appearance.accent_color");
assert(profile_control && profile_control->at("type") == "input-text");
assert(mode_control && mode_control->at("type") == "select");
assert(worker_control && worker_control->at("type") == "input-number");
assert(date_control && date_control->at("type") == "input-date");
assert(color_control && color_control->at("type") == "input-color");
assert(service_form.at("actions").at(1).at("label") == "确认修改");
result = adminive::apply_frontend_patch<Json>(service_config, Json{{"profile_name", "Duplex Profile"}, {"mode", "duplex"}, {"worker_count", 8}, {"receive_gain", 2.5}, {"primary_endpoint", Json{{"enabled", true}, {"host", "10.0.0.1"}, {"port", 9200}}}, {"backup_endpoint", Json{{"enabled", true}, {"host", "10.0.0.2"}, {"port", 9201}}}, {"appearance", Json{{"panel_title", "Duplex Radio"}, {"effective_date", "2026-08-07"}, {"accent_color", "#16a34a"}}}});
assert(result.success);
assert(service_config.mode == Radio_Mode::duplex);
assert(service_config.primary_endpoint.host == "10.0.0.1");
assert(service_config.appearance.accent_color == "#16a34a");
Alert_Config alert_config;
const auto alert_form = adminive::to_amis_form_schema<Json>(alert_config, "/admin/config/alerts/data", "Confirm Changes");
assert(alert_form.at("body").size() == 8);
assert(alert_form.at("body").at(1).at("type") == "input-text");
assert(alert_form.at("body").at(2).at("type") == "select");
assert(alert_form.at("body").at(3).at("type") == "select");
assert(alert_form.at("body").at(4).at("type") == "input-number");
assert(alert_form.at("body").at(5).at("type") == "input-date");
assert(alert_form.at("body").at(6).at("type") == "input-color");
assert(alert_form.at("body").at(7).at("type") == "fieldset");
assert(alert_form.at("body").at(7).at("visibleOn") == "${enabled && channel == 'webhook'}");
const auto alert_view = adminive::describe_edit_view<Alert_Config>();
const auto alert_view_json = adminive::to_view_json<Json, Alert_Config>(alert_view);
assert(alert_view_json.at("body").at("kind") == "vertical");
const auto alert_form = adminive::to_amis_form_schema<Json>(alert_config, alert_view, "/admin/config/alerts/data");
assert(find_named_node(alert_form, "rule_name"));
assert(find_named_node(alert_form, "effective_date")->at("type") == "input-date");
assert(find_named_node(alert_form, "highlight_color")->at("type") == "input-color");
const Json* webhook_group = find_titled_node(alert_form, "Webhook 端点");
assert(webhook_group);
assert(webhook_group->at("visibleOn") == "${enabled && channel == 'webhook'}");
adminive::example::Http_Resource<Radio_Service_Config> service_resource(service_config, "/admin/config/radio");
const auto resource_view = service_resource.view_schema();
assert(resource_view.at("protocol") == "adminive.view");
assert(resource_view.at("kind") == "form");
const auto resource_form = service_resource.amis_schema();
assert(resource_form.at("api").at("method") == "post");
assert(resource_form.at("api").at("url") == "/admin/config/radio/data");