#pragma once #include "adminive/status.hpp" #include #include #include #include #include #include namespace adminive { inline std::string make_field_name(std::string_view prefix, std::string_view name) { if(prefix.empty()) { return std::string(name); } return std::string(prefix) + "." + std::string(name); } template Json make_amis_form_actions(std::string submit_label = "Apply") { Json reset = json_object(); json_set(reset, "type", "reset"); json_set(reset, "label", "Reset"); Json submit = json_object(); json_set(submit, "type", "submit"); json_set(submit, "label", std::move(submit_label)); json_set(submit, "level", "primary"); Json result = json_array(); json_append(result, std::move(reset)); json_append(result, std::move(submit)); return result; } template Json make_amis_control(const Json& field, std::string_view permission, std::string_view prefix = {}) { const std::string name = json_get(Json_Adapter::at(field, "name")); const std::string full_name = make_field_name(prefix, name); const std::string value_type = json_get(Json_Adapter::at(field, "value_type")); if(value_type == "object" && Json_Adapter::contains(field, "children")) { Json body = json_array(); const auto& children = Json_Adapter::at(field, "children"); for(std::size_t index = 0; index < Json_Adapter::size(children); ++index) { const auto& child = Json_Adapter::at(children, index); if(json_get(Json_Adapter::at(child, "visible"))) { json_append(body, make_amis_control(child, permission, full_name)); } } Json control = json_object(); json_set(control, "type", "fieldset"); json_set(control, "title", Json_Adapter::at(field, "label")); json_set(control, "body", std::move(body)); json_set(control, "collapsable", true); json_set(control, "collapsed", false); if(Json_Adapter::contains(field, "description")) { json_set(control, "description", Json_Adapter::at(field, "description")); } if(Json_Adapter::contains(field, "visible_on")) { json_set(control, "visibleOn", Json_Adapter::at(field, "visible_on")); } return control; } Json control = json_object(); json_set(control, "name", full_name); json_set(control, "label", Json_Adapter::at(field, "label")); if(Json_Adapter::contains(field, "description")) { json_set(control, "description", Json_Adapter::at(field, "description")); } if(Json_Adapter::contains(field, "visible_on")) { json_set(control, "visibleOn", Json_Adapter::at(field, "visible_on")); } if(!json_get(Json_Adapter::at(field, permission))) { json_set(control, "type", "static"); return control; } if(Json_Adapter::contains(field, "widget")) { json_set(control, "type", Json_Adapter::at(field, "widget")); } else if(value_type == "boolean") { json_set(control, "type", "switch"); } else if(value_type == "integer" || value_type == "number") { json_set(control, "type", "input-number"); } else if(value_type == "enum") { json_set(control, "type", "select"); } else { json_set(control, "type", "input-text"); } const std::string control_type = json_get(Json_Adapter::at(control, "type")); if(control_type == "input-date") { json_set(control, "valueFormat", "YYYY-MM-DD"); json_set(control, "displayFormat", "YYYY-MM-DD"); json_set(control, "clearable", true); } else if(control_type == "input-color") { json_set(control, "clearable", true); } if(json_get(Json_Adapter::at(field, "required"))) { json_set(control, "required", true); } if(Json_Adapter::contains(field, "minimum")) { json_set(control, "min", Json_Adapter::at(field, "minimum")); } if(Json_Adapter::contains(field, "maximum")) { json_set(control, "max", Json_Adapter::at(field, "maximum")); } if(Json_Adapter::contains(field, "multiple_of")) { json_set(control, "step", Json_Adapter::at(field, "multiple_of")); } if(Json_Adapter::contains(field, "validation_message")) { Json errors = json_object(); json_set(errors, "isInt", Json_Adapter::at(field, "validation_message")); json_set(control, "validationErrors", std::move(errors)); } if(Json_Adapter::contains(field, "options")) { json_set(control, "options", Json_Adapter::at(field, "options")); } return control; } template Json make_amis_form_body(const Json& descriptor, std::string_view permission) { Json body = json_array(); const auto& fields = Json_Adapter::at(descriptor, "fields"); for(std::size_t index = 0; index < Json_Adapter::size(fields); ++index) { const auto& field = Json_Adapter::at(fields, index); if(json_get(Json_Adapter::at(field, "visible"))) { json_append(body, make_amis_control(field, permission)); } } return body; } template Json make_amis_column(const Json& field) { Json column = json_object(); json_set(column, "name", Json_Adapter::at(field, "name")); json_set(column, "label", Json_Adapter::at(field, "list_label")); if(Json_Adapter::contains(field, "order")) { json_set(column, "order", Json_Adapter::at(field, "order")); } if(Json_Adapter::contains(field, "sortable")) { json_set(column, "sortable", Json_Adapter::at(field, "sortable")); } const std::string value_type = json_get(Json_Adapter::at(field, "value_type")); if(value_type == "boolean") { json_set(column, "type", "status"); } else if(value_type == "enum" && Json_Adapter::contains(field, "options")) { json_set(column, "type", "mapping"); Json map = json_object(); const auto& options = Json_Adapter::at(field, "options"); for(std::size_t index = 0; index < Json_Adapter::size(options); ++index) { const auto& option = Json_Adapter::at(options, index); json_set(map, json_get(Json_Adapter::at(option, "value")), Json_Adapter::at(option, "label")); } json_set(column, "map", std::move(map)); } return column; } template Json make_amis_status_service(std::string status_api) { Json view = json_object(); json_set(view, "type", "tpl"); json_set(view, "tpl", R"(
Service${service_state}
Server time${server_time}
Uptime${uptime_seconds} s
Polling sequence${poll_sequence}
Radio states${radio_state_count}
Listen port${listen_port}
)"); Json panel = json_object(); json_set(panel, "type", "panel"); json_set(panel, "title", "Backend Status"); json_set(panel, "body", std::move(view)); Json api = json_object(); json_set(api, "method", "get"); json_set(api, "url", std::move(status_api)); Json result = json_object(); json_set(result, "type", "service"); json_set(result, "name", "backend_status"); json_set(result, "api", std::move(api)); json_set(result, "initFetch", true); json_set(result, "interval", 2000); json_set(result, "silentPolling", true); json_set(result, "showErrorMsg", true); json_set(result, "body", std::move(panel)); return result; } template Json make_amis_object_status_body(const Json& descriptor) { Json body = json_array(); const auto& fields = Json_Adapter::at(descriptor, "fields"); for(std::size_t index = 0; index < Json_Adapter::size(fields); ++index) { const auto& field = Json_Adapter::at(fields, index); const std::string name = json_get(Json_Adapter::at(field, "name")); const std::string label = json_get(Json_Adapter::at(field, "label")); const bool color = json_get(Json_Adapter::at(field, "color")); std::string tpl = "
" + label + "
"; Json item = json_object(); json_set(item, "type", "tpl"); json_set(item, "tpl", std::move(tpl)); json_append(body, std::move(item)); } Json result = json_object(); json_set(result, "type", "container"); json_set(result, "className", "adminive-object-status"); json_set(result, "body", std::move(body)); return result; } template Json make_amis_object_status_service(const Json& descriptor, std::string status_api, std::uint64_t interval) { Json api = json_object(); json_set(api, "method", "get"); json_set(api, "url", std::move(status_api)); Json result = json_object(); json_set(result, "type", "service"); json_set(result, "api", std::move(api)); json_set(result, "initFetch", true); json_set(result, "interval", interval); json_set(result, "silentPolling", true); json_set(result, "showErrorMsg", true); json_set(result, "body", make_amis_object_status_body(descriptor)); return result; } template Json make_amis_object_status_column(const Json& descriptor, std::string status_api, std::uint64_t interval, std::string action_label) { Json pop_over = json_object(); json_set(pop_over, "trigger", "click"); json_set(pop_over, "position", "left-top"); json_set(pop_over, "showIcon", false); json_set(pop_over, "body", make_amis_object_status_service(descriptor, std::move(status_api), interval)); Json result = json_object(); json_set(result, "type", "tpl"); json_set(result, "label", Json_Adapter::at(descriptor, "label")); json_set(result, "tpl", "" + std::move(action_label) + ""); json_set(result, "popOver", std::move(pop_over)); return result; } template Json to_amis_form_schema(const T& value, std::string submit_api = {}, std::string submit_label = "Apply") { const Json descriptor = to_descriptor_json(); Json result = json_object(); json_set(result, "type", "form"); json_set(result, "title", Json_Adapter::at(descriptor, "label")); json_set(result, "data", to_frontend_json(value)); json_set(result, "body", make_amis_form_body(descriptor, "editable")); json_set(result, "actions", make_amis_form_actions(std::move(submit_label))); json_set(result, "affixFooter", true); if(!submit_api.empty()) { Json api = json_object(); json_set(api, "method", "post"); json_set(api, "url", std::move(submit_api)); json_set(result, "api", std::move(api)); } return result; } template Json to_amis_crud_schema(std::string base_api, const Json* status_descriptor = nullptr, std::uint64_t status_interval = 2000) { const Json descriptor = to_descriptor_json(); const Json& list = Json_Adapter::at(descriptor, "list"); const std::string crud_id = json_get(Json_Adapter::at(descriptor, "name")) + "_crud"; Json columns = json_array(); Json id_column = json_object(); json_set(id_column, "name", "id"); json_set(id_column, "label", Json_Adapter::at(list, "id_label")); json_set(id_column, "sortable", true); json_append(columns, std::move(id_column)); std::vector list_fields; const auto& fields = Json_Adapter::at(descriptor, "fields"); for(std::size_t index = 0; index < Json_Adapter::size(fields); ++index) { const auto& field = Json_Adapter::at(fields, index); if(json_get(Json_Adapter::at(field, "readable")) && json_get(Json_Adapter::at(field, "list_visible")) && json_get(Json_Adapter::at(field, "value_type")) != "object") { list_fields.push_back(field); } } std::stable_sort(list_fields.begin(), list_fields.end(), [](const Json& left, const Json& right) { return json_get(Json_Adapter::at(left, "order")) < json_get(Json_Adapter::at(right, "order")); }); for(const auto& field : list_fields) { json_append(columns, make_amis_column(field)); } if(status_descriptor) { json_append(columns, make_amis_object_status_column(*status_descriptor, base_api + "/${id}/status", status_interval, json_get(Json_Adapter::at(list, "view_status_label")))); } const std::string create_label = json_get(Json_Adapter::at(list, "create_label")); const std::string edit_label = json_get(Json_Adapter::at(list, "edit_label")); Json create_api = json_object(); json_set(create_api, "method", "post"); json_set(create_api, "url", base_api); Json create_form = json_object(); json_set(create_form, "type", "form"); json_set(create_form, "api", std::move(create_api)); json_set(create_form, "reload", crud_id); json_set(create_form, "body", make_amis_form_body(descriptor, "creatable")); json_set(create_form, "actions", make_amis_form_actions(create_label)); Json edit_api = json_object(); json_set(edit_api, "method", "put"); json_set(edit_api, "url", base_api + "/${id}"); Json edit_form = json_object(); json_set(edit_form, "type", "form"); json_set(edit_form, "api", std::move(edit_api)); json_set(edit_form, "reload", crud_id); json_set(edit_form, "body", make_amis_form_body(descriptor, "editable")); json_set(edit_form, "actions", make_amis_form_actions(json_get(Json_Adapter::at(list, "confirm_label")))); Json create_dialog = json_object(); json_set(create_dialog, "title", create_label + " " + json_get(Json_Adapter::at(descriptor, "label"))); json_set(create_dialog, "body", std::move(create_form)); Json create_button = json_object(); json_set(create_button, "type", "button"); json_set(create_button, "label", create_label); json_set(create_button, "level", "primary"); json_set(create_button, "actionType", "dialog"); json_set(create_button, "dialog", std::move(create_dialog)); Json edit_dialog = json_object(); json_set(edit_dialog, "title", edit_label + " " + json_get(Json_Adapter::at(descriptor, "label"))); json_set(edit_dialog, "body", std::move(edit_form)); Json edit_button = json_object(); json_set(edit_button, "type", "button"); json_set(edit_button, "label", edit_label); json_set(edit_button, "level", "link"); json_set(edit_button, "actionType", "dialog"); json_set(edit_button, "dialog", std::move(edit_dialog)); Json delete_api = json_object(); json_set(delete_api, "method", "delete"); json_set(delete_api, "url", base_api + "/${id}"); Json delete_button = json_object(); json_set(delete_button, "type", "button"); json_set(delete_button, "label", Json_Adapter::at(list, "delete_label")); json_set(delete_button, "level", "link"); json_set(delete_button, "className", "text-danger"); json_set(delete_button, "actionType", "ajax"); json_set(delete_button, "confirmText", Json_Adapter::at(list, "delete_confirm")); json_set(delete_button, "api", std::move(delete_api)); json_set(delete_button, "reload", crud_id); Json buttons = json_array(); json_append(buttons, std::move(edit_button)); json_append(buttons, std::move(delete_button)); Json operation = json_object(); json_set(operation, "type", "operation"); json_set(operation, "label", Json_Adapter::at(list, "actions_label")); json_set(operation, "buttons", std::move(buttons)); json_append(columns, std::move(operation)); Json toggler = json_object(); json_set(toggler, "type", "columns-toggler"); json_set(toggler, "draggable", Json_Adapter::at(list, "column_reorderable")); Json toolbar = json_array(); json_append(toolbar, std::move(toggler)); json_append(toolbar, "reload"); json_append(toolbar, std::move(create_button)); Json crud_api = json_object(); json_set(crud_api, "method", "get"); json_set(crud_api, "url", base_api); Json crud = json_object(); json_set(crud, "type", "crud"); json_set(crud, "id", crud_id); json_set(crud, "api", std::move(crud_api)); json_set(crud, "syncLocation", false); json_set(crud, "primaryField", "id"); json_set(crud, "headerToolbar", std::move(toolbar)); json_set(crud, "columns", std::move(columns)); const std::string default_order_by = json_get(Json_Adapter::at(list, "default_order_by")); if(!default_order_by.empty()) { Json params = json_object(); json_set(params, "orderBy", default_order_by); json_set(params, "orderDir", Json_Adapter::at(list, "default_order_dir")); json_set(crud, "defaultParams", std::move(params)); } if(json_get(Json_Adapter::at(list, "user_reorderable"))) { json_set(crud, "draggable", true); Json order_api = json_object(); json_set(order_api, "method", "post"); json_set(order_api, "url", base_api + "/order"); json_set(crud, "saveOrderApi", std::move(order_api)); } Json result = json_object(); json_set(result, "type", "page"); json_set(result, "title", Json_Adapter::at(list, "management_label")); json_set(result, "body", std::move(crud)); return result; } template Json to_amis_crud_status_schema(std::string base_api, std::string status_api, const Json* object_status_descriptor = nullptr, std::uint64_t object_status_interval = 2000) { Json result = to_amis_crud_schema(std::move(base_api), object_status_descriptor, object_status_interval); Json crud = std::move(Json_Adapter::at(result, "body")); Json body = json_array(); json_append(body, make_amis_status_service(std::move(status_api))); json_append(body, std::move(crud)); json_set(result, "body", std::move(body)); return result; } }