307 lines
11 KiB
C++
307 lines
11 KiB
C++
#pragma once
|
|
#include "adminive/composition.hpp"
|
|
#include "adminive/json.hpp"
|
|
#include "adminive/view.hpp"
|
|
#include <map>
|
|
#include <string_view>
|
|
namespace adminive {
|
|
inline constexpr std::string_view view_protocol = "adminive.view";
|
|
inline constexpr int view_protocol_version = 1;
|
|
inline constexpr std::string_view composition_manifest_protocol = "adminive.composition-manifest";
|
|
inline constexpr int composition_manifest_protocol_version = 1;
|
|
|
|
inline std::string_view composition_node_kind_name(Composition_Node_Kind value) noexcept {
|
|
switch(value) {
|
|
case Composition_Node_Kind::slot:
|
|
return "slot";
|
|
case Composition_Node_Kind::heading:
|
|
return "heading";
|
|
case Composition_Node_Kind::frontend:
|
|
return "frontend";
|
|
case Composition_Node_Kind::vertical:
|
|
return "vertical";
|
|
case Composition_Node_Kind::horizontal:
|
|
return "horizontal";
|
|
case Composition_Node_Kind::flow:
|
|
return "flow";
|
|
case Composition_Node_Kind::grid:
|
|
return "grid";
|
|
case Composition_Node_Kind::list:
|
|
return "list";
|
|
case Composition_Node_Kind::group:
|
|
return "group";
|
|
case Composition_Node_Kind::card:
|
|
return "card";
|
|
case Composition_Node_Kind::tabs:
|
|
return "tabs";
|
|
case Composition_Node_Kind::tab:
|
|
return "tab";
|
|
}
|
|
return "vertical";
|
|
}
|
|
template <Json_Type Json>
|
|
Json composition_node_to_json(const Composition_Node& node) {
|
|
Json result = json_object<Json>();
|
|
json_set(result, "kind", std::string(composition_node_kind_name(node.kind)));
|
|
if(!node.slot.empty()) {
|
|
json_set(result, "slot", node.slot);
|
|
}
|
|
if(!node.title.empty()) {
|
|
json_set(result, "title", node.title);
|
|
}
|
|
if(!node.description.empty()) {
|
|
json_set(result, "description", node.description);
|
|
}
|
|
if(!node.visible_on.empty()) {
|
|
json_set(result, "visible_on", node.visible_on);
|
|
}
|
|
if(!node.accent_color.empty()) {
|
|
json_set(result, "accent_color", node.accent_color);
|
|
}
|
|
if(node.columns != 0) {
|
|
json_set(result, "columns", node.columns);
|
|
}
|
|
if(node.collapsible) {
|
|
json_set(result, "collapsible", true);
|
|
json_set(result, "collapsed", node.collapsed);
|
|
}
|
|
if(!node.children.empty()) {
|
|
Json children = json_array<Json>();
|
|
for(const auto& child : node.children) {
|
|
json_append(children, composition_node_to_json<Json>(child));
|
|
}
|
|
json_set(result, "children", std::move(children));
|
|
}
|
|
return result;
|
|
}
|
|
template <Json_Type Json>
|
|
Json to_view_json(const Composition_View& view) {
|
|
validate_composition_view(view);
|
|
Json result = json_object<Json>();
|
|
json_set(result, "protocol", view_protocol);
|
|
json_set(result, "protocol_version", view_protocol_version);
|
|
json_set(result, "kind", "composition");
|
|
json_set(result, "name", view.name);
|
|
if(!view.title.empty()) {
|
|
json_set(result, "title", view.title);
|
|
}
|
|
json_set(result, "body", composition_node_to_json<Json>(view.body));
|
|
return result;
|
|
}
|
|
template <Json_Type Json>
|
|
Json to_composition_manifest_json(const Composition_View& view, const std::vector<Composition_Slot_Contract>& contracts, const std::map<std::string, Json>& schemas) {
|
|
validate_composition_slot_contracts(view, contracts);
|
|
Json slots = json_object<Json>();
|
|
for(const auto& contract : contracts) {
|
|
const auto schema = schemas.find(contract.name);
|
|
if(schema == schemas.end()) {
|
|
throw std::invalid_argument("composition slot schema is not provided: " + contract.name);
|
|
}
|
|
Json item = json_object<Json>();
|
|
json_set(item, "component_kind", contract.component_kind);
|
|
if(!contract.descriptor_api.empty()) {
|
|
json_set(item, "descriptor_api", contract.descriptor_api);
|
|
}
|
|
if(!contract.view_api.empty()) {
|
|
json_set(item, "view_api", contract.view_api);
|
|
}
|
|
if(!contract.data_api.empty()) {
|
|
json_set(item, "data_api", contract.data_api);
|
|
}
|
|
if(!contract.amis_api.empty()) {
|
|
json_set(item, "amis_api", contract.amis_api);
|
|
}
|
|
json_set(item, "schema", schema->second);
|
|
json_set(slots, contract.name, std::move(item));
|
|
}
|
|
Json result = json_object<Json>();
|
|
json_set(result, "protocol", composition_manifest_protocol);
|
|
json_set(result, "protocol_version", composition_manifest_protocol_version);
|
|
json_set(result, "view", to_view_json<Json>(view));
|
|
json_set(result, "slots", std::move(slots));
|
|
return result;
|
|
}
|
|
inline std::string_view view_node_kind_name(View_Node_Kind value) noexcept {
|
|
switch(value) {
|
|
case View_Node_Kind::all_fields:
|
|
return "all_fields";
|
|
case View_Node_Kind::field:
|
|
return "field";
|
|
case View_Node_Kind::frontend:
|
|
return "frontend";
|
|
case View_Node_Kind::vertical:
|
|
return "vertical";
|
|
case View_Node_Kind::horizontal:
|
|
return "horizontal";
|
|
case View_Node_Kind::flow:
|
|
return "flow";
|
|
case View_Node_Kind::grid:
|
|
return "grid";
|
|
case View_Node_Kind::list:
|
|
return "list";
|
|
case View_Node_Kind::group:
|
|
return "group";
|
|
case View_Node_Kind::card:
|
|
return "card";
|
|
case View_Node_Kind::tabs:
|
|
return "tabs";
|
|
case View_Node_Kind::tab:
|
|
return "tab";
|
|
}
|
|
return "vertical";
|
|
}
|
|
inline std::string_view form_mode_name(Form_Mode value) noexcept {
|
|
switch(value) {
|
|
case Form_Mode::display:
|
|
return "display";
|
|
case Form_Mode::edit:
|
|
return "edit";
|
|
case Form_Mode::create:
|
|
return "create";
|
|
}
|
|
return "display";
|
|
}
|
|
inline std::string_view table_fixed_name(Table_Fixed value) noexcept {
|
|
switch(value) {
|
|
case Table_Fixed::none:
|
|
return "none";
|
|
case Table_Fixed::left:
|
|
return "left";
|
|
case Table_Fixed::right:
|
|
return "right";
|
|
}
|
|
return "none";
|
|
}
|
|
template <Json_Type Json>
|
|
Json view_node_to_json(const View_Node& node) {
|
|
Json result = json_object<Json>();
|
|
json_set(result, "kind", std::string(view_node_kind_name(node.kind)));
|
|
if(!node.field.empty()) {
|
|
json_set(result, "field", node.field);
|
|
}
|
|
if(!node.title.empty()) {
|
|
json_set(result, "title", node.title);
|
|
}
|
|
if(!node.description.empty()) {
|
|
json_set(result, "description", node.description);
|
|
}
|
|
if(!node.visible_on.empty()) {
|
|
json_set(result, "visible_on", node.visible_on);
|
|
}
|
|
if(node.columns != 0) {
|
|
json_set(result, "columns", node.columns);
|
|
}
|
|
if(node.collapsible) {
|
|
json_set(result, "collapsible", true);
|
|
json_set(result, "collapsed", node.collapsed);
|
|
}
|
|
if(!node.children.empty()) {
|
|
Json children = json_array<Json>();
|
|
for(const auto& child : node.children) {
|
|
json_append(children, view_node_to_json<Json>(child));
|
|
}
|
|
json_set(result, "children", std::move(children));
|
|
}
|
|
return result;
|
|
}
|
|
template <Json_Type Json, Described_Type T>
|
|
Json to_view_json(const Form_View& view) {
|
|
validate_form_view<T>(view);
|
|
Json result = json_object<Json>();
|
|
json_set(result, "protocol", view_protocol);
|
|
json_set(result, "protocol_version", view_protocol_version);
|
|
json_set(result, "kind", "form");
|
|
json_set(result, "name", view.name);
|
|
json_set(result, "title", view.title);
|
|
json_set(result, "mode", std::string(form_mode_name(view.mode)));
|
|
json_set(result, "submit_label", view.submit_label);
|
|
json_set(result, "affix_footer", view.affix_footer);
|
|
json_set(result, "body", view_node_to_json<Json>(view.body));
|
|
return result;
|
|
}
|
|
inline std::string_view collection_mode_name(Collection_Mode value) noexcept {
|
|
switch(value) {
|
|
case Collection_Mode::table:
|
|
return "table";
|
|
case Collection_Mode::list:
|
|
return "list";
|
|
case Collection_Mode::cards:
|
|
return "cards";
|
|
}
|
|
return "table";
|
|
}
|
|
template <Json_Type Json>
|
|
void append_table_view_json(Json& result, const Table_View& view) {
|
|
json_set(result, "name", view.name);
|
|
json_set(result, "title", view.title);
|
|
json_set(result, "id_label", view.id_label);
|
|
json_set(result, "create_label", view.create_label);
|
|
json_set(result, "edit_label", view.edit_label);
|
|
json_set(result, "delete_label", view.delete_label);
|
|
json_set(result, "actions_label", view.actions_label);
|
|
json_set(result, "confirm_label", view.confirm_label);
|
|
json_set(result, "delete_confirm", view.delete_confirm);
|
|
json_set(result, "view_status_label", view.view_status_label);
|
|
json_set(result, "default_order_by", view.default_order_by);
|
|
json_set(result, "default_order_dir", view.default_order_dir);
|
|
json_set(result, "user_reorderable", view.user_reorderable);
|
|
json_set(result, "column_reorderable", view.column_reorderable);
|
|
Json columns = json_array<Json>();
|
|
for(const auto& column : view.columns) {
|
|
Json item = json_object<Json>();
|
|
json_set(item, "field", column.field);
|
|
if(!column.label.empty()) {
|
|
json_set(item, "label", column.label);
|
|
}
|
|
json_set(item, "sortable", column.sortable);
|
|
json_set(item, "searchable", column.searchable);
|
|
json_set(item, "filterable", column.filterable);
|
|
json_set(item, "fixed", std::string(table_fixed_name(column.fixed)));
|
|
json_append(columns, std::move(item));
|
|
}
|
|
json_set(result, "columns", std::move(columns));
|
|
json_set(result, "create_body", view_node_to_json<Json>(view.create_body));
|
|
json_set(result, "edit_body", view_node_to_json<Json>(view.edit_body));
|
|
}
|
|
template <Json_Type Json, Described_Type T>
|
|
Json to_view_json(const Table_View& view) {
|
|
validate_table_view<T>(view);
|
|
Json result = json_object<Json>();
|
|
json_set(result, "protocol", view_protocol);
|
|
json_set(result, "protocol_version", view_protocol_version);
|
|
json_set(result, "kind", "table");
|
|
append_table_view_json(result, view);
|
|
return result;
|
|
}
|
|
template <Json_Type Json, Described_Type T>
|
|
Json to_view_json(const Collection_View& view) {
|
|
validate_collection_view<T>(view);
|
|
Json result = json_object<Json>();
|
|
json_set(result, "protocol", view_protocol);
|
|
json_set(result, "protocol_version", view_protocol_version);
|
|
json_set(result, "kind", "collection");
|
|
json_set(result, "mode", std::string(collection_mode_name(view.mode)));
|
|
append_table_view_json(result, view.table);
|
|
if(view.mode != Collection_Mode::table) {
|
|
Json item = json_object<Json>();
|
|
json_set(item, "title_field", view.item.title_field);
|
|
if(!view.item.subtitle_field.empty()) {
|
|
json_set(item, "subtitle_field", view.item.subtitle_field);
|
|
}
|
|
if(!view.item.accent_field.empty()) {
|
|
json_set(item, "accent_field", view.item.accent_field);
|
|
}
|
|
Json fields = json_array<Json>();
|
|
for(const auto& field : view.item.fields) {
|
|
json_append(fields, field);
|
|
}
|
|
json_set(item, "fields", std::move(fields));
|
|
json_set(result, "item", std::move(item));
|
|
}
|
|
if(view.mode == Collection_Mode::cards) {
|
|
json_set(result, "cards_columns", view.cards_columns);
|
|
}
|
|
return result;
|
|
}
|
|
}
|