准备改adminive

This commit is contained in:
2026-08-12 00:59:34 +08:00
parent abd1b595c7
commit 75795e43bf
14 changed files with 1285 additions and 1698 deletions
+75 -146
View File
@@ -1,5 +1,6 @@
#include "Gallery_Protocol.h"
#include "Gallery_Properties_Adminive.h"
#include "Gallery_Renderables_Adminive.h"
#include "Gallery_Session_Control_Adminive.h"
#include "adminive/adminive.hpp"
#include "adminive/adapters/nlohmann_json.hpp"
@@ -88,10 +89,7 @@ std::vector<Action_Definition> actions(std::string_view case_id,
Gallery_Frame_Mode frame_mode) {
std::vector<Action_Definition> result{
action("reset", "恢复本图默认值", "Gallery_Scene::rebuild", "会话"),
action("rebuild_renderable", "移除并重建控件", "Plot_Core::remove_renderable / Builder::build", "会话"),
action("toggle_view", "切换 View 生命周期", "Plot_Core::activate_view / deactivate_view", "会话"),
action("axis_set_start", "写入坐标范围起点", "Axis::set<&Axis_Properties::coordinates>", "Axis"),
action("axis_set_length", "写入坐标范围跨度", "Axis::set<&Axis_Properties::coordinates>", "Axis"),
action("axis_probe", "读取坐标映射与刻度", "coord_to_pixel / pixel_to_coord / tick_step / sub_tick_count / tick_label", "Axis")
};
if (frame_mode == Gallery_Frame_Mode::Manual) {
@@ -178,67 +176,6 @@ const Case_Model* find_case(std::string_view id) {
Json parse_request(std::string_view message) {
return Json::parse(message.begin(), message.end());
}
template <class Properties>
Gallery_Property_Model make_property_model(Gallery_Frame_Mode frame_mode) {
if(frame_mode == Gallery_Frame_Mode::Low_Latency) {
using T = Gallery_Low_Latency_Case_Properties<Properties>;
return Gallery_Property_Model{std::in_place_type<T>};
}
return Gallery_Property_Model{std::in_place_type<Properties>};
}
Gallery_Property_Model make_property_model(std::string_view case_id, Gallery_Frame_Mode frame_mode) {
if(case_id == "spectrum")
return make_property_model<Gallery_Spectrum_Properties>(frame_mode);
if(case_id == "afterglow")
return make_property_model<Gallery_Afterglow_Properties>(frame_mode);
if(case_id == "sweep_spectrum")
return make_property_model<Gallery_Sweep_Spectrum_Properties>(frame_mode);
if(case_id == "waterfall")
return make_property_model<Gallery_Waterfall_Properties>(frame_mode);
if(case_id == "frequency_trace")
return make_property_model<Gallery_Frequency_Trace_Properties>(frame_mode);
if(case_id == "selection_overlay")
return make_property_model<Gallery_Selection_Overlay_Properties>(frame_mode);
if(case_id == "constellation")
return make_property_model<Gallery_Constellation_Properties>(frame_mode);
return make_property_model<Gallery_Axis_Lab_Properties>(frame_mode);
}
Gallery_Value gallery_value(const Json& value) {
if(value.is_boolean())
return value.get<bool>();
if(value.is_number())
return value.get<double>();
return value.get<std::string>();
}
template <class T>
std::optional<Gallery_Value> property_value(const T& value, std::string_view id) {
std::optional<Gallery_Value> result;
const auto descriptor = adminive::describe<T>();
std::apply([&](const auto&... field) {
([&] {
if(!result && field.name() == id)
result = gallery_value(adminive::encode_json_value<Json>(field.get(value)));
}(), ...);
}, descriptor.fields());
return result;
}
template <class T>
std::size_t property_count(const T&) {
return std::tuple_size_v<adminive::Descriptor_Fields<T>>;
}
template <class T>
Json property_resource(const T& value) {
return {
{"descriptor", adminive::to_descriptor_json<Json, T>()},
{"view", adminive::to_view_json<Json, T>(adminive::describe_edit_view<T>().titled("控件属性").submit("应用"))},
{"data", adminive::to_frontend_json<Json>(value)}
};
}
template <class T>
adminive::Update_Result apply_property_patch(T& value, const Json& patch) {
return adminive::apply_frontend_patch<Json>(value, patch);
}
adminive::Table_View action_view();
} // namespace renderive::web::gallery_detail
@@ -525,27 +462,6 @@ Json frame_mode_contract(Gallery_Frame_Mode mode) {
} // namespace
Gallery_Value gallery_property_value(const Gallery_State& state, std::string_view id) {
const auto result = std::visit([id](const auto& properties) {
return gallery_detail::property_value(properties, id);
}, state.properties);
if(!result)
throw std::out_of_range("gallery property does not exist: " + std::string(id));
return *result;
}
bool gallery_has_property(const Gallery_State& state, std::string_view id) {
return std::visit([id](const auto& properties) {
return gallery_detail::property_value(properties, id).has_value();
}, state.properties);
}
std::size_t gallery_property_count(const Gallery_State& state) {
return std::visit([](const auto& properties) {
return gallery_detail::property_count(properties);
}, state.properties);
}
std::string Gallery_Protocol::catalog_json() {
Json result = protocol_base();
result["type"] = "catalog";
@@ -600,27 +516,23 @@ bool Gallery_Protocol::is_case(std::string_view case_id) {
return gallery_detail::find_case(case_id) != nullptr;
}
Gallery_State Gallery_Protocol::default_state(std::string_view case_id,
Gallery_Frame_Mode frame_mode) {
return {gallery_detail::make_property_model(case_id, frame_mode)};
}
Gallery_State Gallery_Protocol::default_state(std::string_view case_id) {
return default_state(case_id, Gallery_Frame_Mode::Low_Latency);
}
std::string Gallery_Protocol::case_json(std::string_view case_id,
const Gallery_State& state,
std::string_view telemetry_json,
std::string_view notice,
Gallery_Frame_Mode frame_mode) {
std::string Gallery_Protocol::case_json_from_controls(
std::string_view case_id,
std::string_view controls_json,
std::string_view telemetry_json,
std::string_view notice,
Gallery_Frame_Mode frame_mode) {
Json result = protocol_base();
result["type"] = "case_state";
result["case"] = case_contract(case_id);
result["frame_mode"] = frame_mode_contract(frame_mode);
result["controls"] = std::visit([](const auto& properties) {
return gallery_detail::property_resource(properties);
}, state.properties);
try {
result["controls"] = {
{"resources", Json::parse(controls_json.begin(), controls_json.end())}
};
} catch (const std::exception&) {
result["controls"] = {{"resources", Json::array()}};
}
result["actions"] = {
{"descriptor", adminive::to_descriptor_json<Json, gallery_detail::Action_Model>()},
{"view", adminive::to_view_json<Json, gallery_detail::Action_Model>(
@@ -640,14 +552,6 @@ std::string Gallery_Protocol::case_json(std::string_view case_id,
return result.dump();
}
std::string Gallery_Protocol::case_json(std::string_view case_id,
const Gallery_State& state,
std::string_view telemetry_json,
std::string_view notice) {
return case_json(case_id, state, telemetry_json, notice,
Gallery_Frame_Mode::Low_Latency);
}
std::string Gallery_Protocol::error_json(std::string_view message,
std::string_view field) {
Json result = protocol_base();
@@ -674,40 +578,6 @@ std::string Gallery_Protocol::observer_json(std::string_view case_id,
return result.dump();
}
Gallery_Patch_Result Gallery_Protocol::apply_patch(std::string_view case_id,
const Gallery_State& current,
std::string_view message,
Gallery_Frame_Mode frame_mode) {
try {
const Json request = gallery_detail::parse_request(message);
if (!request.is_object() || request.value("category", "") != "event" ||
request.value("type", "") != "gallery_patch" ||
!request.contains("patch") || !request.at("patch").is_object()) {
return {std::nullopt, error_json("gallery_patch 格式无效")};
}
Gallery_State candidate = current;
const auto update = std::visit([&request](auto& properties) {
return gallery_detail::apply_property_patch(properties, request.at("patch"));
}, candidate.properties);
if(!update.success) {
Json response = protocol_base();
response["type"] = "error";
response["message"] = update.message;
response["field_errors"] = update.field_errors;
return {std::nullopt, response.dump()};
}
return {std::move(candidate), {}};
} catch (const std::exception& error) {
return {std::nullopt, error_json(error.what())};
}
}
Gallery_Patch_Result Gallery_Protocol::apply_patch(std::string_view case_id,
const Gallery_State& current,
std::string_view message) {
return apply_patch(case_id, current, message, Gallery_Frame_Mode::Low_Latency);
}
std::optional<Gallery_Open_Request> Gallery_Protocol::open_request(std::string_view message) {
try {
const Json request = gallery_detail::parse_request(message);
@@ -756,9 +626,68 @@ std::optional<Gallery_Action_Request> Gallery_Protocol::action_request(
}
}
std::optional<Gallery_Control_Patch_Request> Gallery_Protocol::control_patch_request(
std::string_view message) {
try {
const Json request = gallery_detail::parse_request(message);
if (!request.is_object() || request.value("category", "") != "event" ||
request.value("type", "") != "gallery_patch" ||
!request.contains("target") || !request.at("target").is_string() ||
!request.contains("patch") || !request.at("patch").is_object())
return std::nullopt;
return Gallery_Control_Patch_Request{
request.at("target").get<std::string>(), request.at("patch").dump()};
} catch (const std::exception&) {
return std::nullopt;
}
}
std::size_t Gallery_Protocol::control_count(std::string_view case_id,
Gallery_Frame_Mode frame_mode) {
return gallery_property_count(default_state(case_id, frame_mode));
const auto count = [](const auto& self, const Json& fields) -> std::size_t {
std::size_t result{};
for (const auto& field : fields) {
if (field.value("editable", false) && !field.contains("children"))
++result;
if (field.contains("children"))
result += self(self, field.at("children"));
}
return result;
};
const auto type_count = [&count]<class T>() {
return count(count, adminive::to_descriptor_json<Json, T>().at("fields"));
};
std::size_t result = type_count.template operator()<Gallery_Session_Control>();
if (case_id == "axis_lab")
return result + type_count.template operator()<Gallery_Frequency_Axis>() +
type_count.template operator()<Gallery_Time_Axis>();
if (case_id == "spectrum" || case_id == "selection_overlay") {
result += type_count.template operator()<Gallery_Frequency_Axis>() +
type_count.template operator()<Gallery_Axis>() +
type_count.template operator()<Gallery_Spectrum>();
if (case_id == "selection_overlay")
result += type_count.template operator()<Gallery_Selection_Rectangle_Overlay>();
return result;
}
if (case_id == "waterfall")
return result + type_count.template operator()<Gallery_Frequency_Axis>() +
type_count.template operator()<Gallery_Time_Axis>() +
type_count.template operator()<Gallery_Waterfall>();
if (case_id == "afterglow")
return result + type_count.template operator()<Gallery_Frequency_Axis>() +
type_count.template operator()<Gallery_Axis>() +
type_count.template operator()<Gallery_Afterglow>();
if (case_id == "sweep_spectrum")
return result + 2 * type_count.template operator()<Gallery_Axis>() +
type_count.template operator()<Gallery_Sweep_Spectrum>();
if (case_id == "frequency_trace")
return result + type_count.template operator()<Gallery_Time_Axis>() +
type_count.template operator()<Gallery_Axis>() +
type_count.template operator()<Gallery_Frequency_Trace>();
if (case_id == "constellation")
return result + 2 * type_count.template operator()<Gallery_Axis>() +
type_count.template operator()<Gallery_Constellation_Diagram>();
return result;
}
std::size_t Gallery_Protocol::control_count(std::string_view case_id) {