#include "adminive/adminive.hpp" #include "adminive/adapters/nlohmann_json.hpp" #include #include #include namespace view_test { using Json = nlohmann::json; struct Config { std::string name{"Alpha"}; int count{3}; bool enabled{true}; std::string color{"#336699"}; std::string read_only{"fixed"}; }; } namespace adminive { template <> struct Type_Descriptor { static auto get() { using T = view_test::Config; return object("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(), ADMINIVE_FIELD(T, read_only).label("Read Only").text_input()); } }; template <> struct Type_View_Descriptor { static Form_View edit() { using T = view_test::Config; return edit_form(vertical(group("Identity", horizontal(use<&T::name>(), use<&T::enabled>(), use<&T::read_only>())), 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(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>(), use<&T::read_only>())); } static Collection_View collection() { Collection_View result; result.table = table(); result.table.name = "view_config_collection"; return result; } }; } int main() { using view_test::Config; using view_test::Json; const auto descriptor = adminive::to_descriptor_json(); 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(); adminive::validate_form_view(form_view); const auto form_json = adminive::to_view_json(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(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(2).at("items").at(0).at("type") == "container"); assert(form_amis.at("body").at(2).at("items").at(1).at("type") == "container"); assert(form_amis.at("body").at(2).at("items").at(0).at("body").at(0).at("type") == "card"); assert(form_amis.at("body").at(3).at("type") == "tabs"); assert(form_amis.at("data").at("read_only") == "fixed"); assert(form_amis.at("api").at("data").at("name") == "${name}"); assert(form_amis.at("api").at("data").at("count") == "${count}"); assert(form_amis.at("api").at("data").at("enabled") == "${enabled}"); assert(form_amis.at("api").at("data").at("color") == "${color}"); assert(!form_amis.at("api").at("data").contains("read_only")); const auto table_view = adminive::describe_table_view(); adminive::validate_table_view(table_view); const auto table_json = adminive::to_view_json(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(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(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 five_columns = adminive::composition_view("five_columns", adminive::compose::horizontal(adminive::compose::slot("a"), adminive::compose::slot("b"), adminive::compose::slot("c"), adminive::compose::slot("d"), adminive::compose::slot("e"))); const auto five_columns_amis = adminive::to_amis_composition_schema(five_columns, {{"a", Json{{"type", "tpl"}}}, {"b", Json{{"type", "tpl"}}}, {"c", Json{{"type", "tpl"}}}, {"d", Json{{"type", "tpl"}}}, {"e", Json{{"type", "tpl"}}}}); const auto& five_widths = five_columns_amis.at("body").at(0).at("columns"); assert(five_widths.at(0).at("md") == 3); assert(five_widths.at(1).at("md") == 3); assert(five_widths.at(2).at("md") == 2); assert(five_widths.at(3).at("md") == 2); assert(five_widths.at(4).at("md") == 2); const auto flow_composition = adminive::composition_view("flow_page", adminive::compose::flow(adminive::compose::slot("left"), adminive::compose::slot("right"))); const auto flow_amis = adminive::to_amis_composition_schema(flow_composition, {{"left", Json{{"type", "tpl"}, {"tpl", "left"}}}, {"right", Json{{"type", "tpl"}, {"tpl", "right"}}}}); assert(flow_amis.at("body").at(0).at("type") == "flex"); assert(flow_amis.at("body").at(0).at("items").at(0).at("type") == "container"); assert(flow_amis.at("body").at(0).at("items").at(1).at("type") == "container"); const auto list_composition = adminive::composition_view("list_page", adminive::compose::list(adminive::compose::slot("left"), adminive::compose::slot("right"))); const auto list_composition_json = adminive::to_view_json(list_composition); assert(list_composition_json.at("body").at("kind") == "list"); const auto list_composition_amis = adminive::to_amis_composition_schema(list_composition, {{"left", Json{{"type", "tpl"}, {"tpl", "left"}}}, {"right", Json{{"type", "tpl"}, {"tpl", "right"}}}}); assert(list_composition_amis.at("body").at(0).at("type") == "container"); assert(list_composition_amis.at("body").at(0).at("body").size() == 2); const auto frontend_composition = adminive::composition_view("frontend_page", adminive::compose::frontend(adminive::compose::slot("left"), adminive::compose::slot("right"))); const auto frontend_composition_json = adminive::to_view_json(frontend_composition); assert(frontend_composition_json.at("body").at("kind") == "frontend"); const auto frontend_composition_amis = adminive::to_amis_composition_schema(frontend_composition, {{"left", Json{{"type", "tpl"}, {"tpl", "left"}}}, {"right", Json{{"type", "tpl"}, {"tpl", "right"}}}}); assert(frontend_composition_amis.at("body").at(0).at("className") == "adminive-frontend-placement"); const std::vector slot_contracts{{"left", "amis_schema", "/left/descriptor", "/left/view", "/left/data", "/left/amis"}, {"right", "amis_schema", "/right/descriptor", "/right/view", "/right/data", "/right/amis"}}; const auto manifest = adminive::to_composition_manifest_json(frontend_composition, slot_contracts, {{"left", Json{{"type", "tpl"}, {"tpl", "left"}}}, {"right", Json{{"type", "tpl"}, {"tpl", "right"}}}}); assert(manifest.at("protocol") == "adminive.composition-manifest"); assert(manifest.at("view").at("body").at("kind") == "frontend"); assert(manifest.at("slots").at("left").at("view_api") == "/left/view"); assert(manifest.at("slots").at("right").at("schema").at("tpl") == "right"); const auto frontend_form = adminive::edit_form(adminive::frontend(adminive::list(adminive::use<&Config::name>(), adminive::use<&Config::count>()))); const auto frontend_form_json = adminive::to_view_json(frontend_form); assert(frontend_form_json.at("body").at("kind") == "frontend"); assert(frontend_form_json.at("body").at("children").at(0).at("kind") == "list"); const auto table_amis = adminive::to_amis_table_schema("/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); const auto& create_submit_data = table_amis.at("body").at(0).at("headerToolbar").at(2).at("dialog").at("body").at("api").at("data"); assert(create_submit_data.at("name") == "${name}"); assert(create_submit_data.at("count") == "${count}"); assert(create_submit_data.at("enabled") == "${enabled}"); assert(create_submit_data.at("color") == "${color}"); assert(!create_submit_data.contains("read_only")); const auto& edit_submit_data = table_amis.at("body").at(0).at("columns").back().at("buttons").at(0).at("dialog").at("body").at("api").at("data"); assert(edit_submit_data.at("name") == "${name}"); assert(edit_submit_data.at("count") == "${count}"); assert(edit_submit_data.at("enabled") == "${enabled}"); assert(edit_submit_data.at("color") == "${color}"); assert(!edit_submit_data.contains("read_only")); const auto list_amis = adminive::to_amis_list_schema("/configs", table_view, Json{{"title", "${name}"}}); assert(list_amis.at("body").at(0).at("mode") == "list"); assert(list_amis.at("body").at(0).at("id") == "view_config_table_crud_list"); assert(!list_amis.at("body").at(0).contains("columns")); assert(list_amis.at("body").at(0).at("listItem").at("actions").size() == 2); assert(list_amis.at("body").at(0).at("listItem").at("actions").at(0).at("dialog").at("body").at("reload") == "view_config_table_crud_list"); assert(list_amis.at("body").at(0).at("listItem").at("actions").at(1).at("reload") == "view_config_table_crud_list"); assert(list_amis.at("body").at(0).at("headerToolbar").size() == 2); assert(list_amis.at("body").at(0).at("headerToolbar").at(1).at("dialog").at("body").at("reload") == "view_config_table_crud_list"); const auto cards_amis = adminive::to_amis_cards_schema("/configs", table_view, Json{{"header", Json{{"title", "${name}"}}}}, 2); assert(cards_amis.at("body").at(0).at("mode") == "cards"); assert(cards_amis.at("body").at(0).at("id") == "view_config_table_crud_cards"); assert(cards_amis.at("body").at(0).at("columnsCount") == 2); assert(cards_amis.at("body").at(0).at("card").at("actions").size() == 2); assert(cards_amis.at("body").at(0).at("card").at("actions").at(1).at("reload") == "view_config_table_crud_cards"); const auto item_view = adminive::collection_item<&Config::name>().subtitle<&Config::color>().accent<&Config::color>().body<&Config::count, &Config::enabled>(); const auto collection_view = adminive::describe_collection_view(); const auto labeled_collection = collection_view.id_title("Record").create_title("Add").edit_title("Change").delete_title("Remove").actions_title("Operations").confirm_title("Apply").delete_confirmation("Remove record?").status_title("Status"); assert(labeled_collection.table.id_label == "Record"); assert(labeled_collection.table.create_label == "Add"); assert(labeled_collection.table.edit_label == "Change"); assert(labeled_collection.table.delete_label == "Remove"); assert(labeled_collection.table.actions_label == "Operations"); assert(labeled_collection.table.confirm_label == "Apply"); assert(labeled_collection.table.delete_confirm == "Remove record?"); assert(labeled_collection.table.view_status_label == "Status"); const auto semantic_list_view = collection_view.as_list(item_view); const auto semantic_list_json = adminive::to_view_json(semantic_list_view); assert(semantic_list_json.at("kind") == "collection"); assert(semantic_list_json.at("mode") == "list"); assert(semantic_list_json.at("item").at("title_field") == "name"); assert(semantic_list_json.at("item").at("fields").at(0) == "count"); const auto semantic_list_amis = adminive::to_amis_collection_schema("/configs", semantic_list_view); assert(semantic_list_amis.at("body").at(0).at("id") == "view_config_collection_crud_list"); assert(semantic_list_amis.at("body").at(0).at("listItem").at("title") == "${name}"); assert(semantic_list_amis.at("body").at(0).at("listItem").at("actions").at(1).at("reload") == "view_config_collection_crud_list"); const auto semantic_cards_view = collection_view.as_cards(item_view, 4); const auto semantic_cards_json = adminive::to_view_json(semantic_cards_view); assert(semantic_cards_json.at("mode") == "cards"); assert(semantic_cards_json.at("cards_columns") == 4); const auto semantic_cards_amis = adminive::to_amis_collection_schema("/configs", semantic_cards_view); assert(semantic_cards_amis.at("body").at(0).at("id") == "view_config_collection_crud_cards"); assert(semantic_cards_amis.at("body").at(0).at("columnsCount") == 4); const auto semantic_table_json = adminive::to_view_json(collection_view.as_table()); assert(semantic_table_json.at("mode") == "table"); adminive::Collection_Service 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_manifest{}; try { adminive::to_composition_manifest_json(frontend_composition, {adminive::Composition_Slot_Contract{"left", "amis_schema", {}, {}, {}, {}}}, {{"left", Json{{"type", "tpl"}}}}); } catch(const std::invalid_argument&) { invalid_manifest = true; } assert(invalid_manifest); bool invalid_grid{}; try { adminive::validate_form_view(adminive::edit_form(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(adminive::edit_form(adminive::tabs(adminive::use<&Config::name>()))); } catch(const std::invalid_argument&) { invalid_tabs = true; } assert(invalid_tabs); bool invalid_tab_position{}; try { adminive::validate_form_view(adminive::edit_form(adminive::tab("Invalid", adminive::use<&Config::name>()))); } catch(const std::invalid_argument&) { invalid_tab_position = true; } assert(invalid_tab_position); bool invalid_composition_tab_position{}; try { adminive::validate_composition_view(adminive::composition_view("invalid", adminive::compose::tab("Invalid", adminive::compose::slot("x")))); } catch(const std::invalid_argument&) { invalid_composition_tab_position = true; } assert(invalid_composition_tab_position); bool invalid_sort{}; try { adminive::validate_table_view(adminive::table_view(adminive::column<&Config::name>()).default_sort("name")); } catch(const std::invalid_argument&) { invalid_sort = true; } assert(invalid_sort); return 0; }