{"id":27279135,"url":"https://github.com/coolshare/newframework-schemadriven","last_synced_at":"2026-01-23T10:17:34.869Z","repository":{"id":257827990,"uuid":"145343858","full_name":"coolshare/NewFramework-SchemaDriven","owner":"coolshare","description":null,"archived":false,"fork":false,"pushed_at":"2018-09-28T00:38:07.000Z","size":228,"stargazers_count":2,"open_issues_count":0,"forks_count":1,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-11T17:52:39.948Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coolshare.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2018-08-19T23:07:43.000Z","updated_at":"2024-09-29T02:08:53.000Z","dependencies_parsed_at":null,"dependency_job_id":"115a892b-d81d-44da-a3f7-aaf47feaa51a","html_url":"https://github.com/coolshare/NewFramework-SchemaDriven","commit_stats":null,"previous_names":["coolshare/newframework-schemadriven"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/coolshare/NewFramework-SchemaDriven","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolshare%2FNewFramework-SchemaDriven","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolshare%2FNewFramework-SchemaDriven/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolshare%2FNewFramework-SchemaDriven/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolshare%2FNewFramework-SchemaDriven/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coolshare","download_url":"https://codeload.github.com/coolshare/NewFramework-SchemaDriven/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coolshare%2FNewFramework-SchemaDriven/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28687439,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-23T05:48:07.525Z","status":"ssl_error","status_checked_at":"2026-01-23T05:48:07.129Z","response_time":59,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-04-11T17:47:59.437Z","updated_at":"2026-01-23T10:17:34.861Z","avatar_url":"https://github.com/coolshare.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"New Framework: a Schema Driven UI\n=================================\n\nBy Mark Qian 8/2018 (markqian@hotmail.com)\n\n\u003cb\u003eA. Introduction:\u003c/b\u003e\u003cbr/\u003e \nA Schema-driven UI: I am not the first one doing this but happened to have the similar idea with what others had:\u003cbr/\u003e\n\u003cul\u003e\n  \u003ca href=\"https://medium.com/@hintology/sdd-schema-driven-development-f1d232d73ea6\" target=_blank\u003eSDD — Schema Driven Development\u003c/a\u003e\u003cbr/\u003e\n  \u003ca href=\"https://github.com/mozilla-services/react-jsonschema-form\" target=_blank\u003ereact-jsonschema-form\u003c/a\u003e\u003cbr/\u003e\n  ...\n\u003c/ul\u003e\nThe \"thing\" to be driven by schema is view renderers. Many people accept using a renderer for a table but very few develops/architects do the same thing for another majority type of view, form.  People keep writing html tags for forms redundantly. \u003cb\u003eWe should think about this in a different way\u003c/b\u003e: the form info (schema) is the input data of form renderer instead of html codes. In my project, each type of view such as form, table, D3 diagram has a renderer.\u003cbr/\u003e\u003cbr/\u003e\nThe major benefits include:\u003cbr/\u003e\n\u003cul\u003e\n  \u003cli\u003eLoading view data automatically\u003c/li\u003e\n  \u003cli\u003eCollecting view data for submission automatically\u003c/li\u003e\n  \u003cli\u003eFor most regular view like regular forms and tables, the views are rendered by \"built-in\" framework renderers. So no layout coding for the framework users\u003c/li\u003e\n  \u003cli\u003eValidation in a systematic way\u003c/li\u003e\n  \u003cli\u003eUnit Testing in a systematic way\u003c/li\u003e\n\u003c/ul\u003e\n\n\u003cbr/\u003e\u003c/br/\u003e\nHere is the \u003cb\u003eflow of schema driven\u003c/b\u003e in my approach:\u003cbr/\u003e\u003cbr/\u003e\n\u003cimg src=\"https://github.com/coolshare/NewFramework-SchemaDriven/blob/master/ClassDiagram.png\"/\u003e\u003cbr/\u003e\n\u003cul\u003e\n  \u003cdiv\u003e\u003cb\u003e1. Models delivered by server\u003c/b\u003e (either generated from model-driven server side or given memually to UI).\u003cbr/\u003e\n      \u003cul\u003e\n        \u003cp\u003e Models defined by server contain: a field list where each field has attributes like name, data type and validation info like the following:\u003cbr/\u003e\n\u003cpre\u003e\n    {\n      \"Student\":{\n        \"fields\": [\n          {\"name\":\"id\", \"type\":\"string\", \"validate\":[]},\n          {\"name\":\"name\", \"type\":\"string\", \"validate\":[\"required\"]},\n          {\"name\":\"age\", \"type\":\"int\", \"validate\":[\"required\", \"int\"]},\n          {\"name\":\"campus\", \"type\":\"enum\", \"validate\":[\"required\", \"int\"], \"typeMap\":{\"0\":\"Hayward\", \"1\":\"San Jose\", \"2\":\"SF\"},\n            ...\n        ]  \n      },\n      \"Teacher\":{\n        \"fields\": [\n          {\"name\":\"id\", \"type\":\"string\", \"validate\":[]},\n          {\"name\":\"name\", \"type\":\"string\", \"validate\":[\"required\"]},\n            ...\n        ]  \n      },\n      \"Course\":{\n        \"fields\": [\n          {\"name\":\"id\", \"type\":\"string\", \"validate\":[]},\n          {\"name\":\"name\", \"type\":\"string\", \"validate\":[\"required\"]},\n            ...\n        ]  \n      },\n      \"Campus\":{\n        \"fields\": [\n          {\"name\":\"id\", \"type\":\"enum\", \"validate\":[], \"typeMap\":{\"0\":\"Hayward\", \"1\":\"San Jose\", \"2\":\"SF\"},\n          {\"name\":\"name\", \"type\":\"string\", \"validate\":[\"required\"]},\n          {\"name\":\"address\", \"type\":\"string\", \"validate\":[\"required\"]},  \n          {\"name\":\"totalStuden\", \"type\":\"int\", \"validate\":[]},  \n            ...\n        ]  \n      }\n\u003c/pre\u003e \n        \u003c/p\u003e\n      \u003c/ul\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\u003cb\u003e2. UI use the models from server as \"super\" classes to generate \"schemas\"\u003c/b\u003e.\n    \u003cul\u003e\n        \u003cp\u003e A schema contains more UI related info besides info in its model: formType, tableType, renderStle and so on. This \"schema\" work as a primitive UI image for that component/field, like the following:\u003cbr/\u003e\n\u003cpre\u003e\n    {\n      \"Student\":{\n        \"fields\": [\n          {\"name\":\"id\", props:{\"formType\":\"Hidden\", \"tableType\":\"Hidden\"}},\n          {\"name\":\"name\", props:{\"formType\":\"Input\", \"tableType\":\"text\"}},\n          {\"name\":\"age\", props:{\"formType\":\"Input\", \"tableType\":\"text\"}},\n            ...\n        ]  \n      }\n\u003c/pre\u003e\n      The framework will generate a \"default\" schema for each model while the props specified in schema above overwrites props in generated default props. So if no specified in schema, defaults will be applied like \"formType\":\"Input\" and \"tableType\":\"text\".\n      \u003c/p\u003e\n      \u003c/ul\u003e\n  \u003c/div\u003e\n  \u003cdiv\u003e\u003cb\u003e3. UI defines \"views\", as instances of schemas, to be used by each individual screen out of \"schemas\" above.\u003c/b\u003e\n    \u003cul\u003e\n        \u003cp\u003e A schema can be used in many views and a view may use different fields from different schemas. In many of our screen, a \"visual form\" could consist of fields from different server model  objects. For example, you may want to show couple \"forms\" on your page with fields like student name, student favor course, student campus address, like the following:\u003cbr/\u003e\n\u003cpre\u003e\n    {\n      \"StudentView\":{\n        \"fieldList\": [\n          {\"path\":\"Student.name\"},\n          {\"path\":\"Student.id\"},\n          {\"path\":\"Course.name\", props:{\"label\":\"Most frequently taking course\"}},\n          {\"path\":\"Campus.name\", props:{\"typeList\":\u003cb\u003e[\"1\", \"2\", \"0\"]\u003c/b\u003e}},\n            ...\n        ]  \n      },\n      \"TeacherView\":{\n        \"fieldList\": [\n          {\"path\":\"Teacher.name\"},\n          {\"path\":\"Student.name\", props:{\"label\":\"Favor Student\"}},\n          {\"path\":\"Course.name\", props:{\"label\":\"Most frequently involved course\"}},\n          {\"path\":\"Campus.name\", props:{\"label\":\"Closest campus\", \"typeList\":\u003cb\u003e[\"0\", \"2\", \"1\"]\u003c/b\u003e}},\n            ...\n        ]  \n      },\n      //Nested View\n      \"CombinedView\": {\n        \"fields\": [\n          {\"name\":\"studenView\", props:{\"schemaName\":\"StudentView\", \"showFun\":function() {return this.getValue(\"CurrentView}===\"student\"}},\n          {\"name\":\"teacherView\", props:{\"schemaName\":\"TeacherView\", \"showFun\":function() {return this.getValue(\"CurrentView}===\"teacher\"}},\n            ...\n        ]  \n      }\n\u003c/pre\u003e\n      As you can see above, fields in each view definition will overwrite the props with the same name in the \"schema\" so that each view can have its own characters. For example, \"StudentView\" and \"TeacherView\" both contain \"Campus.name\" but each wants to display the campus names in its own order so they use \"typeList\" to tell the order differently. View can be nested like \"CombinedView\" above\n      \u003c/p\u003e\n      \u003c/ul\u003e\n  \u003c/div\u003e\n\u003ca name=\"UIRendersViews\"\u003e\u003c/a\u003e\n\u003cdiv\u003e\u003cb\u003e4. UI Renders Views\u003c/b\u003e. \n    \u003cul\u003e\n        \u003cp\u003e My framework provides a variety of renderers like Form, Table, D3Canvas, LineChart and so on. In this way, it is much easy to apply systematic approaches like validation, submission, data loading. For example, for most \"regular\" forms, \u003cb\u003ethere is not codes are needed to load and submit data\u003c/b\u003e since the framework will introspect the \"fieldList\" in views above to obtain what need to be loaded and submitted: for \"TeacherView\", the framework needs to load data from model/object Teacher, Student and Campus and similarly when submiting.\n      \u003c/p\u003e\n      \u003c/ul\u003e\n  \u003c/div\u003e\n\u003ca name=\"UIHandlingApplicationLogic\"\u003e\u003c/a\u003e\n\u003cdiv\u003e\u003cb\u003e5. UI Handling Application Logic\u003c/b\u003e. \n    \u003cul\u003e\n        \u003cp\u003e Any application built with my framework is a container containing isolated \"Objects\" (UI views and service). This objects has no  knowledge about others or the \"application logic\". For example, let's take a look at a navigation view, HeaderTab:\n\u003cpre\u003e\n      \"HeaderTab\":{\n        \"fields\": [\n          {\"name\":\"StudentTab\", \"props\":{\"formType\":\"Button\", \"\u003cb\u003eroute\u003c/b\u003e\":{\"viewType\":\"Screen\"}}},\n          {\"name\":\"TeacherTab\", \"props\":{\"formType\":\"Button\", \"route\":{\"viewType\":\"Screen\"}}},\n          {\"name\":\"CampusTab\", \"props\":{\"formType\":\"Button\", \"route\":{\"viewType\":\"Dialog\"}}},\n            ...\n        ]  \n      }\n\u003c/pre\u003e \n      As you can see above, there is only a \"route\" attribute that includes no info about what to do after \"StudentTab\" is clicked! This is key of my design: \u003cb\u003eno appliaction logic resides in codes!\u003c/b\u003e. The application logic will be loaded as data at runtime in json file as following:\n\u003cpre\u003e\n  \"Route\":{\n      \"HeaderTab.StudentTab\":\"StudentView\",\n      \"HeaderTab.TeacherTab\":\"TeacherView\",\n      \"HeaderTab.CampusTab\":\"CampusTabView\",\n        ... \n  }\n\u003c/pre\u003e\n      The key of the map above is the unique id of each field such as \"HeaderTab.StudentTab\" and the value is the unique name of the view\n      \u003c/p\u003e\n      \u003c/ul\u003e\n  \u003c/div\u003e\n\u003ca name=\"EachFieldHandleSpecialInteraction\"\u003e\u003c/a\u003e\n\u003cdiv\u003e\u003cb\u003e6. Each Field Handle Special Interaction\u003c/b\u003e. \n    \u003cul\u003e\n        \u003cp\u003e Each field may have some special need to send or received event/data. So Pub/Sub is now in place. For example, when the field \"Campus.name\" in \"StudentView\" is changed, we want to give \"CanpusView\" a chance to update its \"Canpus.totalStuden\":\n\u003cpre\u003e\n    {\n      \"StudentView\":{\n        \"fieldList\": [\n          {\"path\":\"Student.name\"},\n          {\"path\":\"Student.id\"},\n          {\"path\":\"Course.name\", props:{\"label\":\"Most frequently taking course\"}},\n          {\"path\":\"Campus.name\", props:{\"typeList\":[\"1\", \"2\", \"0\"], \"\u003cb\u003epub\u003c/b\u003e\":{\"topic\":\"/Updated/StudentView/Campus.name\", {\"event\":\"change\"}}},\n            ...\n        ]  \n      },\n      \"CanpusView\":{\n        \"fieldList\": [\n          {\"path\":\"Canpus.name\"},\n          {\"path\":\"Canpus.totalStuden\", props:{\"label\":\"Total Number of Student\"}},\n            ...\n        ],\n        \"props\":{\n            \"\u003cb\u003esub\u003c/b\u003e\":{\"topic\":\"/Updated/StudentView/Campus.name\", \"handler\":function() {\n              //make update here\n              \n            }            \n        }\n      }\n\u003c/pre\u003e   \nAs you can see above, field \"Campus.name\" register a topic \"/Updated/StudentView/Campus.name\" for an event of \"change\" and \"CanpusView\" subscribe the topic at view level and then handle the update there.\n      \u003c/p\u003e\n      \u003c/ul\u003e\n  \u003c/div\u003e\n\n\n(More coming soon)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolshare%2Fnewframework-schemadriven","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoolshare%2Fnewframework-schemadriven","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoolshare%2Fnewframework-schemadriven/lists"}