分层重构
This commit is contained in:
@@ -134,12 +134,12 @@ struct Control_Adapter<advanced_test::Color_Code, advanced_test::Json> {
|
||||
advanced_test::Json result;
|
||||
result["type"] = "input-color";
|
||||
result["name"] = make_field_name(context.prefix, field.at("name").get<std::string>());
|
||||
result["label"] = field.at("label");
|
||||
result["label"] = field.at("presentation").at("label");
|
||||
result["clearable"] = true;
|
||||
return result;
|
||||
}
|
||||
static advanced_test::Json make_column(const advanced_test::Json& field) {
|
||||
return advanced_test::Json{{"type", "tpl"}, {"name", field.at("name")}, {"label", field.at("list_label")}, {"tpl", "<span style=\"color:${color}\">${color}</span>"}};
|
||||
return advanced_test::Json{{"type", "tpl"}, {"name", field.at("name")}, {"label", field.at("presentation").at("label")}, {"tpl", "<span style=\"color:${color}\">${color}</span>"}};
|
||||
}
|
||||
};
|
||||
template <>
|
||||
@@ -171,7 +171,7 @@ template <>
|
||||
struct Type_Descriptor<advanced_test::Control_Config> {
|
||||
static auto get() {
|
||||
using T = advanced_test::Control_Config;
|
||||
return object<T>("control", "Control", ADMINIVE_FIELD(T, color).editable().list_label("颜色"));
|
||||
return object<T>("control", "Control", ADMINIVE_FIELD(T, color).editable().label("颜色"));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
@@ -255,7 +255,14 @@ template <>
|
||||
struct Type_Descriptor<advanced_test::Invalid_Sort_Config> {
|
||||
static auto get() {
|
||||
using T = advanced_test::Invalid_Sort_Config;
|
||||
return object<T>("invalid_sort", "Invalid Sort", ADMINIVE_FIELD(T, value)).default_sort("value");
|
||||
return object<T>("invalid_sort", "Invalid Sort", ADMINIVE_FIELD(T, value));
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_View_Descriptor<advanced_test::Invalid_Sort_Config> {
|
||||
static Table_View table() {
|
||||
using T = advanced_test::Invalid_Sort_Config;
|
||||
return table_view<T>(column<&T::value>()).default_sort("value");
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -299,10 +306,10 @@ int main() {
|
||||
assert(managed_inherited.field<0>().snapshot() == 12);
|
||||
assert(managed_inherited.field<1>().snapshot() == "changed");
|
||||
Control_Config controls;
|
||||
const auto control_form = adminive::to_amis_form_schema<Json>(controls);
|
||||
const auto control_form = adminive::to_amis_form_schema<Json>(controls, adminive::describe_edit_view<Control_Config>());
|
||||
assert(control_form.at("body").at(0).at("type") == "input-color");
|
||||
Device_Config devices;
|
||||
const auto device_form = adminive::to_amis_form_schema<Json>(devices);
|
||||
const auto device_form = adminive::to_amis_form_schema<Json>(devices, adminive::describe_edit_view<Device_Config>());
|
||||
assert(device_form.at("body").at(0).at("type") == "fieldset");
|
||||
assert(device_form.at("body").at(0).at("body").at(0).at("type") == "select");
|
||||
assert(device_form.at("body").at(0).at("body").at(1).at("body").at(2).at("type") == "input-color");
|
||||
@@ -333,7 +340,7 @@ int main() {
|
||||
assert(duplicate_rejected);
|
||||
bool invalid_sort_rejected{};
|
||||
try {
|
||||
static_cast<void>(adminive::to_descriptor_json<Json, Invalid_Sort_Config>());
|
||||
adminive::validate_table_view<Invalid_Sort_Config>(adminive::describe_table_view<Invalid_Sort_Config>());
|
||||
} catch(const std::invalid_argument&) {
|
||||
invalid_sort_rejected = true;
|
||||
}
|
||||
|
||||
@@ -22,6 +22,13 @@ struct Type_Descriptor<drogon_test::Config> {
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_View_Descriptor<drogon_test::Config> {
|
||||
static Table_View table() {
|
||||
using T = drogon_test::Config;
|
||||
return table_view<T>(column<&T::name>("Name").sort().search());
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_Descriptor<drogon_test::Status> {
|
||||
static auto get() {
|
||||
using T = drogon_test::Status;
|
||||
@@ -63,9 +70,15 @@ int main() {
|
||||
assert(app.filters("/config/data", drogon::Post).size() == 2);
|
||||
assert(app.filters("/status/data", drogon::Get).size() == 2);
|
||||
auto request = std::make_shared<drogon::HttpRequest>();
|
||||
drogon::HttpResponsePtr response;
|
||||
app.handle("/config/view", drogon::Get, request, [&response](const drogon::HttpResponsePtr& value) {
|
||||
response = value;
|
||||
});
|
||||
assert(response->status == drogon::k200OK);
|
||||
assert(Json::parse(response->body).at("data").at("kind") == "form");
|
||||
request->body = R"({"name":"updated"})";
|
||||
request->user = "wyc";
|
||||
drogon::HttpResponsePtr response;
|
||||
response.reset();
|
||||
app.handle("/config/data", drogon::Post, request, [&response](const drogon::HttpResponsePtr& value) {
|
||||
response = value;
|
||||
});
|
||||
@@ -102,7 +115,14 @@ int main() {
|
||||
assert(response->status == drogon::k200OK);
|
||||
adminive::Drogon_Collection_Resource<drogon_test::Config, Json> collection("/configs", {drogon_test::Config{"first"}});
|
||||
collection.bind(app, options);
|
||||
request->parameters = {{"page", "1"}, {"perPage", "10"}};
|
||||
response.reset();
|
||||
app.handle("/configs/view", drogon::Get, request, [&response](const drogon::HttpResponsePtr& value) {
|
||||
response = value;
|
||||
});
|
||||
assert(response->status == drogon::k200OK);
|
||||
assert(Json::parse(response->body).at("data").at("kind") == "table");
|
||||
assert(Json::parse(response->body).at("data").at("columns").at(0).at("searchable") == true);
|
||||
request->parameters = {{"page", "1"}, {"perPage", "10"}, {"name", "fir"}};
|
||||
response.reset();
|
||||
app.handle("/configs", drogon::Get, request, [&response](const drogon::HttpResponsePtr& value) {
|
||||
response = value;
|
||||
|
||||
@@ -115,7 +115,7 @@ int main() {
|
||||
assert(Probe_Lock::exclusive_locks.load(std::memory_order_relaxed) == 0);
|
||||
assert(Probe_Lock::shared_locks.load(std::memory_order_relaxed) == 0);
|
||||
const auto descriptor = adminive::to_descriptor_json<Json, Section_Config>();
|
||||
assert(descriptor.at("protocol_version") == 4);
|
||||
assert(descriptor.at("protocol_version") == 5);
|
||||
assert(!descriptor.at("fields").at(0).contains("lock_mode"));
|
||||
assert(descriptor.at("fields").at(0).at("writable") == true);
|
||||
assert(descriptor.at("fields").at(0).at("synchronized") == true);
|
||||
|
||||
@@ -276,7 +276,7 @@ int main() {
|
||||
update = adminive::apply_frontend_create<Json>(created, Json{{"child", Json{{"editable_value", 5}}}});
|
||||
assert(!update.success);
|
||||
assert(update.field_errors.contains("child.required_value"));
|
||||
const auto root_form = adminive::to_amis_form_schema<Json>(root);
|
||||
const auto root_form = adminive::to_amis_form_schema<Json>(root, adminive::describe_edit_view<Root_Config>());
|
||||
assert(root_form.at("body").at(0).at("body").at(2).at("visibleOn") == "${child.editable_value > 0}");
|
||||
Numeric_Config numeric;
|
||||
update = adminive::apply_frontend_patch<Json>(numeric, Json{{"signed_value", 1.5}});
|
||||
@@ -286,7 +286,7 @@ int main() {
|
||||
update = adminive::apply_frontend_patch<Json>(numeric, Json{{"signed_value", std::numeric_limits<std::uint64_t>::max()}});
|
||||
assert(!update.success);
|
||||
Optional_Config optional;
|
||||
const auto optional_form = adminive::to_amis_form_schema<Json>(optional);
|
||||
const auto optional_form = adminive::to_amis_form_schema<Json>(optional, adminive::describe_edit_view<Optional_Config>());
|
||||
assert(optional_form.at("body").at(0).at("clearable") == true);
|
||||
assert(optional_form.at("body").at(1).at("clearable") == true);
|
||||
update = adminive::apply_frontend_patch<Json>(optional, Json{{"count", nullptr}, {"note", nullptr}});
|
||||
|
||||
+120
-56
@@ -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");
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
#include "adminive/adminive.hpp"
|
||||
#include "adminive/adapters/nlohmann_json.hpp"
|
||||
#include <cassert>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
namespace view_test {
|
||||
using Json = nlohmann::json;
|
||||
struct Config {
|
||||
std::string name{"Alpha"};
|
||||
int count{3};
|
||||
bool enabled{true};
|
||||
std::string color{"#336699"};
|
||||
};
|
||||
}
|
||||
namespace adminive {
|
||||
template <>
|
||||
struct Type_Descriptor<view_test::Config> {
|
||||
static auto get() {
|
||||
using T = view_test::Config;
|
||||
return object<T>("view_config", "View Config", ADMINIVE_FIELD(T, name).editable().creatable().label("Name").text_input(), ADMINIVE_FIELD(T, count).editable().creatable().label("Count").number_input(), ADMINIVE_FIELD(T, enabled).editable().creatable().label("Enabled").boolean_input(), ADMINIVE_FIELD(T, color).editable().creatable().label("Color").color_input());
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct Type_View_Descriptor<view_test::Config> {
|
||||
static Form_View edit() {
|
||||
using T = view_test::Config;
|
||||
return edit_form<T>(vertical(group("Identity", horizontal(use<&T::name>(), use<&T::enabled>())), grid(2, use<&T::count>(), card("Appearance", use<&T::color>())), flow(card("Name Card", use<&T::name>()), card("Count Card", use<&T::count>())), tabs(tab("General", use<&T::name>(), use<&T::count>()), tab("Visual", use<&T::color>())))).submit("Save");
|
||||
}
|
||||
static Table_View table() {
|
||||
using T = view_test::Config;
|
||||
return table_view<T>(column<&T::name>("Name").search().fix(Table_Fixed::left), column<&T::count>("Count").sort(), column<&T::enabled>("Enabled").filter(), column<&T::color>("Color")).titled("Configs").default_sort("count", true).create_layout(grid(2, use<&T::name>(), use<&T::count>(), use<&T::enabled>(), use<&T::color>())).edit_layout(vertical(use<&T::name>(), horizontal(use<&T::count>(), use<&T::enabled>()), use<&T::color>()));
|
||||
}
|
||||
};
|
||||
}
|
||||
int main() {
|
||||
using view_test::Config;
|
||||
using view_test::Json;
|
||||
const auto descriptor = adminive::to_descriptor_json<Json, Config>();
|
||||
assert(descriptor.at("fields").at(0).at("presentation").at("label") == "Name");
|
||||
assert(descriptor.at("fields").at(0).at("presentation").at("control") == "text");
|
||||
assert(!descriptor.at("fields").at(0).contains("sortable"));
|
||||
const auto form_view = adminive::describe_edit_view<Config>();
|
||||
adminive::validate_form_view<Config>(form_view);
|
||||
const auto form_json = adminive::to_view_json<Json, Config>(form_view);
|
||||
assert(form_json.at("kind") == "form");
|
||||
assert(form_json.at("body").at("kind") == "vertical");
|
||||
assert(form_json.at("body").at("children").at(0).at("kind") == "group");
|
||||
assert(form_json.at("body").at("children").at(1).at("kind") == "grid");
|
||||
assert(form_json.at("body").at("children").at(2).at("kind") == "flow");
|
||||
assert(form_json.at("body").at("children").at(3).at("kind") == "tabs");
|
||||
Config config;
|
||||
const auto form_amis = adminive::to_amis_form_schema<Json>(config, form_view, "/config/data");
|
||||
assert(form_amis.at("type") == "form");
|
||||
assert(form_amis.at("actions").at(1).at("label") == "Save");
|
||||
assert(form_amis.at("body").at(0).at("type") == "fieldset");
|
||||
assert(form_amis.at("body").at(1).at("type") == "grid");
|
||||
assert(form_amis.at("body").at(2).at("type") == "flex");
|
||||
assert(form_amis.at("body").at(3).at("type") == "tabs");
|
||||
const auto table_view = adminive::describe_table_view<Config>();
|
||||
adminive::validate_table_view<Config>(table_view);
|
||||
const auto table_json = adminive::to_view_json<Json, Config>(table_view);
|
||||
assert(table_json.at("kind") == "table");
|
||||
assert(table_json.at("columns").at(0).at("searchable") == true);
|
||||
assert(table_json.at("columns").at(0).at("fixed") == "left");
|
||||
assert(table_json.at("columns").at(1).at("sortable") == true);
|
||||
assert(table_json.at("columns").at(2).at("filterable") == true);
|
||||
assert(table_json.at("default_order_by") == "count");
|
||||
assert(table_json.at("default_order_dir") == "desc");
|
||||
const auto composition = adminive::composition_view("config_page", adminive::compose::vertical(adminive::compose::heading("Config Page").accent("#123456"), adminive::compose::horizontal(adminive::compose::slot("form"), adminive::compose::slot("table"))));
|
||||
const auto composition_json = adminive::to_view_json<Json>(composition);
|
||||
assert(composition_json.at("kind") == "composition");
|
||||
assert(composition_json.at("body").at("children").at(0).at("kind") == "heading");
|
||||
const auto composition_amis = adminive::to_amis_composition_schema<Json>(composition, {{"form", form_amis}, {"table", Json{{"type", "tpl"}, {"tpl", "table"}}}});
|
||||
assert(composition_amis.at("body").at(0).at("type") == "tpl");
|
||||
assert(composition_amis.at("body").at(1).at("type") == "grid");
|
||||
const auto table_amis = adminive::to_amis_table_schema<Json, Config>("/configs", table_view);
|
||||
assert(table_amis.at("type") == "page");
|
||||
assert(table_amis.at("body").at(0).at("columns").at(1).at("searchable") == true);
|
||||
assert(table_amis.at("body").at(0).at("columns").at(2).at("sortable") == true);
|
||||
assert(table_amis.at("body").at(0).at("columns").at(3).at("filterable") == true);
|
||||
adminive::Collection_Service<Config, Json, adminive::No_Lock> collection("/configs", {Config{"Alpha", 3, true, "#111111"}, Config{"Beta", 7, false, "#222222"}, Config{"Alphabet", 5, true, "#333333"}});
|
||||
adminive::Collection_Query query;
|
||||
query.fields["name"] = "alpha";
|
||||
auto response = collection.list_response(query);
|
||||
assert(response.status == 200);
|
||||
assert(response.body.at("data").at("total") == 2);
|
||||
assert(response.body.at("data").at("items").at(0).at("count") == 5);
|
||||
query = {};
|
||||
query.fields["enabled"] = "true";
|
||||
response = collection.list_response(query);
|
||||
assert(response.status == 200);
|
||||
assert(response.body.at("data").at("total") == 2);
|
||||
query = {};
|
||||
query.order_by = "count";
|
||||
query.order_dir = "asc";
|
||||
response = collection.list_response(query);
|
||||
assert(response.status == 200);
|
||||
assert(response.body.at("data").at("items").at(0).at("count") == 3);
|
||||
query = {};
|
||||
query.fields["color"] = "#111111";
|
||||
response = collection.list_response(query);
|
||||
assert(response.status == 400);
|
||||
bool invalid_grid{};
|
||||
try {
|
||||
adminive::validate_form_view<Config>(adminive::edit_form<Config>(adminive::grid(0, adminive::use<&Config::name>())));
|
||||
} catch(const std::invalid_argument&) {
|
||||
invalid_grid = true;
|
||||
}
|
||||
assert(invalid_grid);
|
||||
bool invalid_tabs{};
|
||||
try {
|
||||
adminive::validate_form_view<Config>(adminive::edit_form<Config>(adminive::tabs(adminive::use<&Config::name>())));
|
||||
} catch(const std::invalid_argument&) {
|
||||
invalid_tabs = true;
|
||||
}
|
||||
assert(invalid_tabs);
|
||||
bool invalid_sort{};
|
||||
try {
|
||||
adminive::validate_table_view<Config>(adminive::table_view<Config>(adminive::column<&Config::name>()).default_sort("name"));
|
||||
} catch(const std::invalid_argument&) {
|
||||
invalid_sort = true;
|
||||
}
|
||||
assert(invalid_sort);
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user