Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve performance when dealing with large json content #252

Open
j2jensen opened this issue Dec 20, 2018 · 34 comments
Open

Improve performance when dealing with large json content #252

j2jensen opened this issue Dec 20, 2018 · 34 comments

Comments

@j2jensen
Copy link
Contributor

j2jensen commented Dec 20, 2018

Expected behavior

People want to be able to drill down through a large json document to make changes to a few specific parts of it.

Actual behavior

Loading a large json document causes the browser to do a lot of processing. On slower machines, this can even cause the browser to warn the user that the page is unresponsive and prompt them to kill the tab.

Profiling appears to indicate that most of the CPU time is spent building out DOM elements, most of which are never seen because they're collapsed or on tabs that don't get accessed.

It seems to me that by lazily constructing collapsed elements the UI could load pretty much immediately, and the portions that need to be built when the user selects a particular tab or expands a particular collapsed object could usually be built quickly enough to go unnoticed by the user.

Or if there's another way to optimize the construction of the DOM elements to improve performance by orders of magnitude, that would work too.

Steps to reproduce the behavior

Schema

JSON Schema
{
  "$schema": "http://json-schema.org/draft-04/schema",
  "id": "http://www.healthcatalyst.com/schema/prb-config-schema.json",
  "title": "Registry Builder Configuration",
  "options": {
    "disable_collapse": true,
    "disable_properties": true
  },
  "type": "object",
  "properties": {
    "$schema": {
      "type": "string",
      "options": {
        "hidden": true
      }
    },
    "edw": {
      "$ref": "#/definitions/edwConfig",
      "propertyOrder": 1,
      "options": {
        "collapsed": true
      }
    },
    "uiSettings": {
      "$ref": "#/definitions/uiSettingsConfig",
      "propertyOrder": 2,
      "options": {
        "collapsed": true
      }
    },
    "grains": {
      "$ref": "#/definitions/grains",
      "propertyOrder": 3,
      "options": {
        "collapsed": true,
        "disable_array_delete_last_row": true
      }
    },
    "valueSetSettings": {
      "$ref": "#/definitions/valueSetSettings",
      "propertyOrder": 4,
      "options": {
        "collapsed": true
      }
    }
  },
  "required": [
    "edw",
    "grains"
  ],
  "additionalProperties": false,
  "definitions": {
    "edwConfig": {
      "type": "object",
      "title": "EDW",
      "format": "grid",
      "description": "foobar",
      "properties": {
        "connectionString": {
          "type": "string",
          "options": {
            "grid_columns": 12
          },
          "description": "foobar"
        },
        "commandTimeout": {
          "type": "integer",
          "format": "number",
          "options": {
            "grid_columns": 2
          },
          "description": "foobar"
        },
        "disableRegistries": {
          "type": "boolean",
          "description": "foobar",
          "options": {
            "grid_columns": 12
          }
        }
      },
      "required": [
        "connectionString",
        "commandTimeout"
      ],
      "additionalProperties": false
    },
    "uiSettingsConfig": {
      "type": "object",
      "title": "UI Settings",
      "format": "grid",
      "description": "foobar",
      "properties": {
        "title": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 8
          }
        },
        "basicUserMinResultCount": {
          "type": "integer",
          "format": "number",
          "description": "foobar",
          "options": {
            "grid_columns": 4
          }
        },
        "logo": {
          "$ref": "#/definitions/imageType",
          "options": {
            "grid_columns": 12,
            "collapsed": true
          }
        }
      },
      "required": [
        "title",
        "logo"
      ],
      "additionalProperties": false
    },
    "valueSetSettings": {
      "type": "object",
      "title": "Value Sets",
      "format": "grid",
      "description": "foobar",
      "properties": {
        "enabled": {
          "type": "boolean",
          "description": "foobar",
          "options": {
            "grid_columns": 12
          }
        },
        "terminologyUrl": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 12
          }
        },
        "authorityDescription": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 6
          }
        },
        "clientCode": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 6
          }
        }
      },
      "required": [
        "enabled",
        "terminologyUrl",
        "authorityDescription",
        "clientCode"
      ],
      "additionalProperties": false
    },
    "grains": {
      "title": "Filter Grains",
      "format": "tabs",
      "type": "array",
      "description": "foobar",
      "items": {
        "$ref": "#/definitions/grain"
      },
      "additionalProperties": false
    },
    "results": {
      "title": "Ruleset Result Columns",
      "type": "object",
      "description": "foobar",
      "properties": {
        "columns": {
          "title": "Columns",
          "type": "array",
          "format": "tabs",
          "options": {
            "disable_collapse": true,
            "disable_array_delete_last_row": true
          },
          "items": {
            "$ref": "#/definitions/column"
          }
        }
      },
      "required": [
        "columns"
      ],
      "additionalProperties": false
    },
    "column": {
      "headerTemplate": "{{self.title}}",
      "type": "object",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "title": {
          "type": "string",
          "description": "foobar"
        },
        "column": {
          "type": "string",
          "description": "foobar"
        },
        "alias": {
          "type": "string",
          "description": "foobar"
        },
        "includeInSearch": {
          "type": "boolean",
          "description": "foobar"
        }
      },
      "required": [
        "title",
        "column",
        "includeInSearch"
      ],
      "additionalProperties": false
    },
    "grain": {
      "title": "Filter Grain",
      "headerTemplate": "{{self.grainKey}}",
      "type": "object",
      "description": "foobar",
      "properties": {
        "grainKey": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 5
          }
        },
        "entityName": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 5
          }
        },
        "entityIdField": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 5
          }
        },
        "results": {
          "$ref": "#/definitions/results",
          "options": {
            "grid_columns": 12
          }
        },
        "uiName": {
          "$ref": "#/definitions/grainName"
        },
        "filterTypes": {
          "$ref": "#/definitions/filterTypes"
        }
      },
      "required": [
        "entityName",
        "entityIdField",
        "uiName",
        "filterTypes"
      ],
      "additionalProperties": false
    },
    "grainName": {
      "title": "Grain Name",
      "type": "object",
      "format": "grid",
      "description": "foobar",
      "properties": {
        "singular": {
          "type": "string",
          "options": {
            "grid_columns": 6
          }
        },
        "plural": {
          "type": "string",
          "options": {
            "grid_columns": 6
          }
        }
      },
      "required": [
        "singular",
        "plural"
      ],
      "additionalProperties": false
    },
    "imageType": {
      "title": "Application Logo",
      "type": "object",
      "description": "foobar",
      "properties": {
        "location": {
          "type": "string"
        },
        "base64": {
          "type": "string",
          "format": "textarea"
        }
      },
      "additionalProperties": false
    },
    "filterTypes": {
      "title": "Filter Types",
      "format": "tabs",
      "type": "array",
      "description": "foobar",
      "items": {
        "$ref": "#/definitions/filterType"
      }
    },
    "filterType": {
      "title": "Filter Type",
      "headerTemplate": "{{self.name}}",
      "type": "object",
      "format": "grid",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "isMainGrain": {
          "title": "Main-Grained Filter",
          "type": "boolean",
          "description": "foobar",
          "format": "checkbox",
          "options": {
            "grid_columns": 12
          }
        },
        "disabledForScenes": {
          "$ref": "#/definitions/filterDisabledForScenes",
          "options": {
            "grid_columns": 6
          }
        },
        "disabledForFilters": {
          "$ref": "#/definitions/filterDisabledForFilters",
          "options": {
            "grid_columns": 6
          }
        },
        "uiIndex": {
          "type": "integer",
          "format": "number",
          "description": "foobar",
          "options": {
            "grid_columns": 2
          }
        },
        "name": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 5
          }
        },
        "filterTypeKey": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 5
          }
        },
        "comments": {
          "$ref": "#/definitions/comments"
        },
        "helpText": {
          "$ref": "#/definitions/helpText"
        },
        "filterJoins": {
          "type": "array",
          "title": "Filter Joins",
          "description": "foobar",
          "options": {
            "collapsed": true,
            "grid_columns": 12
          },
          "items": {
            "$ref": "#/definitions/filterJoin"
          }
        },
        "filterCriteria": {
          "type": "array",
          "title": "Additonal Filter Criteria",
          "description": "foobar",
          "options": {
            "collapsed": true,
            "grid_columns": 12
          },
          "items": {
            "title": "Criterion",
            "type": "string",
            "pattern": "\\S"
          }
        },
        "filterComponents": {
          "title": "Filter Components",
          "description": "foobar",
          "type": "array",
          "items": {
            "$ref": "#/definitions/filterComponent"
          },
          "format": "tabs",
          "options": {
            "collapsed": true,
            "grid_columns": 12,
            "disable_array_delete_last_row": true
          }
        },
        "uiFilterComponentGroups": {
          "title": "Filter Component Groups",
          "description": "foobar",
          "type": "array",
          "format": "tabs",
          "options": {
            "collapsed": true,
            "disable_array_delete_last_row": true
          },
          "items": {
            "$ref": "#/definitions/uiFilterComponentGroup"
          }
        },
        "aggregates": {
          "title": "Advanced Aggregate Functions",
          "description": "foobar",
          "options": {
            "collapsed": true,
            "grid_columns": 12
          },
          "type": "object",
          "properties": {
            "count": {
              "title": "Count",
              "description": "foobar",
              "type": "object",
              "properties": {
                "enabled": {
                  "description": "foobar",
                  "type": "boolean"
                },
                "distinctFieldOptions": {
                  "title": "Count Distinct",
                  "description": "foobar",
                  "options": {
                    "collapsed": true
                  },
                  "type": "array",
                  "format": "tabs",
                  "items": {
                    "$ref": "#/definitions/configuredField"
                  }
                }
              }
            }
          }
        }
      },
      "required": [
        "isMainGrain",
        "name",
        "filterJoins",
        "filterTypeKey",
        "uiIndex",
        "disabledForScenes",
        "disabledForFilters"
      ],
      "additionalProperties": false
    },
    "configuredField": {
      "title": "Configured Field",
      "type": "object",
      "properties": {
        "key": {
          "type": "string",
          "description": "foobar"
        },
        "title": {
          "type": "string",
          "description": "foobar"
        },
        "fieldName": {
          "type": "string",
          "description": "foobar"
        }
      },
      "required": [
        "key",
        "title",
        "fieldName"
      ]
    },
    "uiFilterComponentGroup": {
      "title": "Component Group",
      "type": "object",
      "options": {
        "disable_collapse": true,
        "remove_empty_properties": true
      },
      "properties": {
        "label": {
          "type": "string",
          "description": "foobar"
        },
        "filterComponentKeys": {
          "title": "Component Keys",
          "type": "array",
          "description": "foobar",
          "items": {
            "type": "string"
          }
        }
      },
      "required": [
        "filterComponentKeys"
      ]
    },
    "filterComponent": {
      "title": "Filter Component",
      "headerTemplate": "{{self.uiConfig.name}}",
      "type": "object",
      "oneOf": [
        {
          "$ref": "#/definitions/multiSelectFilterComponent"
        },
        {
          "$ref": "#/definitions/valueSetMultiSelectFilterComponent"
        },
        {
          "$ref": "#/definitions/mixedMultiSelectFilterComponent"
        },
        {
          "$ref": "#/definitions/singleSelectFilterComponent"
        },
        {
          "$ref": "#/definitions/dateRangeFilterComponent"
        },
        {
          "$ref": "#/definitions/rangeFilterComponent"
        }
      ],
      "required": [
        "typeKey"
      ]
    },
    "multiSelectFilterComponent": {
      "title": "MultiSelect",
      "description": "foobar",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "filterComponentKey": {
          "type": "string",
          "description": "foobar"
        },
        "typeKey": {
          "type": "string",
          "options": {
            "hidden": true
          },
          "description": "foobar",
          "enum": [
            "MultiSelect"
          ]
        },
        "uiConfig": {
          "title": "UI Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "foobar"
            },
            "codeIsSignificant": {
              "type": "boolean",
              "description": "foobar"
            },
            "allowCSV": {
              "type": "boolean",
              "description": "foobar"
            },
            "isMacro": {
              "type": "boolean",
              "description": "foobar"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "helpText": {
              "$ref": "#/definitions/helpText"
            }
          },
          "additionalProperties": false,
          "required": [
            "name"
          ]
        },
        "config": {
          "title": "Component Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "valueSelector": {
              "title": "Value Selector",
              "type": "string",
              "description": "foobar"
            },
            "selectOptions": {
              "options": {
                "collapsed": false
              },
              "$ref": "#/definitions/filterComponentSelectOptions"
            },
            "dependsOn": {
              "options": {
                "collapsed": true
              },
              "$ref": "#/definitions/dependsOn"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            }
          },
          "additionalProperties": false,
          "required": [
            "valueSelector",
            "selectOptions"
          ]
        },
        "disabledForScenes": {
          "$ref": "#/definitions/componentDisabledForScenes"
        },
        "disabledForFilters": {
          "$ref": "#/definitions/componentDisabledForFilters"
        }
      },
      "additionalProperties": false,
      "required": [
        "filterComponentKey",
        "typeKey",
        "config",
        "uiConfig",
        "disabledForScenes",
        "disabledForFilters"
      ]
    },
    "valueSetMultiSelectFilterComponent": {
      "title": "Value Set MultiSelect",
      "description": "foobar",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "filterComponentKey": {
          "type": "string",
          "description": "foobar"
        },
        "typeKey": {
          "type": "string",
          "options": {
            "hidden": true
          },
          "description": "foobar",
          "enum": [
            "ValueSetMultiSelect"
          ]
        },
        "uiConfig": {
          "title": "UI Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "foobar"
            },
            "codeIsSignificant": {
              "type": "boolean",
              "description": "foobar"
            },
            "allowCSV": {
              "type": "boolean",
              "description": "foobar"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "helpText": {
              "$ref": "#/definitions/helpText"
            }
          },
          "additionalProperties": false,
          "required": [
            "name"
          ]
        },
        "config": {
          "title": "Component Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "valueSelector": {
              "title": "Value Selector",
              "type": "string",
              "description": "foobar"
            },
            "valueSetCodeCriteria": {
              "options": {
                "collapsed": true
              },
              "title": "Value Set Code Criteria",
              "type": "array",
              "description": "foobar",
              "items": {
                "type": "object",
                "properties": {
                  "comments": {
                    "$ref": "#/definitions/comments"
                  },
                  "codeSystemGuid": {
                    "type": "string",
                    "description": "foobar"
                  }
                },
                "additionalProperties": false,
                "required": [
                  "codeSystemGuid"
                ]
              }
            },
            "comments": {
              "$ref": "#/definitions/comments"
            }
          },
          "additionalProperties": false,
          "required": [
            "valueSelector",
            "valueSetCodeCriteria"
          ]
        },
        "disabledForScenes": {
          "$ref": "#/definitions/componentDisabledForScenes"
        },
        "disabledForFilters": {
          "$ref": "#/definitions/componentDisabledForFilters"
        }
      },
      "additionalProperties": false,
      "required": [
        "filterComponentKey",
        "typeKey",
        "config",
        "uiConfig",
        "disabledForScenes",
        "disabledForFilters"
      ]
    },
    "mixedMultiSelectFilterComponent": {
      "title": "Mixed Type MultiSelect",
      "description": "foobar",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "filterComponentKey": {
          "type": "string",
          "description": "foobar"
        },
        "typeKey": {
          "type": "string",
          "options": {
            "hidden": true
          },
          "description": "foobar",
          "enum": [
            "MixedMultiSelect"
          ]
        },
        "uiConfig": {
          "title": "UI Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "foobar"
            },
            "numericName": {
              "type": "string",
              "description": "foobar"
            },
            "textName": {
              "type": "string",
              "description": "foobar"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "helpText": {
              "$ref": "#/definitions/helpText"
            }
          },
          "additionalProperties": false,
          "required": [
            "name"
          ]
        },
        "config": {
          "title": "Component Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "textValueSelector": {
              "type": "string",
              "description": "foobar"
            },
            "numberValueSelector": {
              "type": "string",
              "description": "foobar"
            },
            "dependsOn": {
              "options": {
                "collapsed": true
              },
              "$ref": "#/definitions/dependsOn"
            }
          },
          "additionalProperties": false,
          "required": [
            "textValueSelector",
            "numberValueSelector",
            "dependsOn"
          ]
        },
        "disabledForScenes": {
          "$ref": "#/definitions/componentDisabledForScenes"
        },
        "disabledForFilters": {
          "$ref": "#/definitions/componentDisabledForFilters"
        }
      },
      "additionalProperties": false,
      "required": [
        "filterComponentKey",
        "typeKey",
        "config",
        "uiConfig",
        "disabledForScenes",
        "disabledForFilters"
      ]
    },
    "rangeFilterComponent": {
      "title": "Number Range",
      "description": "foobar",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "filterComponentKey": {
          "type": "string",
          "description": "foobar"
        },
        "typeKey": {
          "type": "string",
          "options": {
            "hidden": true
          },
          "description": "foobar",
          "enum": [
            "NumberRange"
          ]
        },
        "uiConfig": {
          "title": "UI Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "foobar"
            },
            "max": {
              "type": "number",
              "description": "foobar"
            },
            "min": {
              "type": "number",
              "description": "foobar"
            },
            "unit": {
              "options": {
                "collapsed": true
              },
              "$ref": "#/definitions/unit"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "helpText": {
              "$ref": "#/definitions/helpText"
            }
          },
          "additionalProperties": false,
          "required": [
            "name"
          ]
        },
        "config": {
          "title": "Component Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "valueSelector": {
              "title": "Value Selector",
              "type": "string",
              "description": "foobar"
            },
            "selectOptions": {
              "options": {
                "collapsed": false
              },
              "$ref": "#/definitions/filterComponentSelectOptions"
            }
          },
          "additionalProperties": false,
          "required": [
            "valueSelector",
            "selectOptions"
          ]
        },
        "disabledForScenes": {
          "$ref": "#/definitions/componentDisabledForScenes"
        },
        "disabledForFilters": {
          "$ref": "#/definitions/componentDisabledForFilters"
        }
      },
      "additionalProperties": false,
      "required": [
        "filterComponentKey",
        "typeKey",
        "config",
        "uiConfig",
        "disabledForScenes",
        "disabledForFilters"
      ]
    },
    "singleSelectFilterComponent": {
      "title": "Single Select",
      "description": "foobar",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "filterComponentKey": {
          "type": "string",
          "description": "foobar"
        },
        "typeKey": {
          "type": "string",
          "description": "foobar",
          "enum": [
            "Select",
            "Registry"
          ]
        },
        "uiConfig": {
          "title": "UI Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "foobar"
            },
            "placeholderText": {
              "type": "string",
              "description": "foobar"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "helpText": {
              "$ref": "#/definitions/helpText"
            }
          },
          "additionalProperties": false,
          "required": [
            "name"
          ]
        },
        "config": {
          "title": "Component Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "valueSelector": {
              "title": "Value Selector",
              "type": "string",
              "description": "foobar"
            },
            "selectOptions": {
              "options": {
                "collapsed": false
              },
              "$ref": "#/definitions/filterComponentSelectOptions"
            },
            "dependsOn": {
              "options": {
                "collapsed": true
              },
              "$ref": "#/definitions/dependsOn"
            },
            "comments": {
              "$ref": "#/definitions/comments"
            }
          },
          "additionalProperties": false,
          "required": [
            "valueSelector",
            "selectOptions"
          ]
        },
        "disabledForScenes": {
          "$ref": "#/definitions/componentDisabledForScenes"
        },
        "disabledForFilters": {
          "$ref": "#/definitions/componentDisabledForFilters"
        }
      },
      "additionalProperties": false,
      "required": [
        "filterComponentKey",
        "typeKey",
        "config",
        "uiConfig",
        "disabledForScenes",
        "disabledForFilters"
      ]
    },
    "dateRangeFilterComponent": {
      "title": "Temporal Constraint",
      "description": "foobar",
      "options": {
        "disable_collapse": true
      },
      "properties": {
        "filterComponentKey": {
          "type": "string",
          "description": "foobar"
        },
        "typeKey": {
          "type": "string",
          "options": {
            "hidden": true
          },
          "description": "foobar",
          "enum": [
            "TemporalConstraint"
          ]
        },
        "uiConfig": {
          "title": "UI Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "description": "foobar"
            },
            "displayMode": {
              "type": "string",
              "description": "foobar",
              "enum": [
                "Default",
                "Age"
              ]
            },
            "comments": {
              "$ref": "#/definitions/comments"
            },
            "helpText": {
              "$ref": "#/definitions/helpText"
            }
          },
          "additionalProperties": false,
          "required": [
            "name"
          ]
        },
        "config": {
          "title": "Component Configuration",
          "options": {
            "collapsed": true
          },
          "type": "object",
          "properties": {
            "dateSelector": {
              "type": "string"
            },
            "dependsOn": {
              "options": {
                "collapsed": true
              },
              "$ref": "#/definitions/dependsOn"
            }
          },
          "additionalProperties": false,
          "required": [
            "dateSelector"
          ]
        },
        "disabledForScenes": {
          "$ref": "#/definitions/componentDisabledForScenes"
        },
        "disabledForFilters": {
          "$ref": "#/definitions/componentDisabledForFilters"
        }
      },
      "additionalProperties": false,
      "required": [
        "filterComponentKey",
        "typeKey",
        "config",
        "uiConfig",
        "disabledForScenes",
        "disabledForFilters"
      ]
    },
    "filterComponentSelectOptions": {
      "type": "object",
      "title": "Value Options Source",
      "description": "foobar",
      "properties": {
        "comments": {
          "$ref": "#/definitions/comments"
        },
        "table": {
          "$ref": "#/definitions/nonEmptyOrWhiteSpaceString",
          "description": "foobar"
        },
        "codeSelector": {
          "$ref": "#/definitions/nonEmptyOrWhiteSpaceString",
          "description": "foobar"
        },
        "titleSelector": {
          "$ref": "#/definitions/nonEmptyOrWhiteSpaceString",
          "description": "foobar"
        }
      },
      "required": [
        "table",
        "codeSelector",
        "titleSelector"
      ],
      "additionalProperties": false
    },
    "filterJoin": {
      "type": "object",
      "format": "grid",
      "title": "Filter Join",
      "options": {
        "remove_empty_properties": true
      },
      "properties": {
        "joinTargetName": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 4
          }
        },
        "joinIdField": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 4
          }
        },
        "sourceIdField": {
          "type": "string",
          "description": "foobar",
          "options": {
            "grid_columns": 4
          }
        }
      },
      "required": [
        "joinTargetName",
        "joinIdField"
      ]
    },
    "comments": {
      "type": "string",
      "title": "Comments",
      "format": "textarea",
      "propertyOrder": 1001,
      "description": "foobar",
      "options": {
        "grid_columns": 12
      }
    },
    "helpText": {
      "type": "string",
      "title": "Help Text",
      "format": "textarea",
      "propertyOrder": 1000,
      "description": "foobar",
      "options": {
        "grid_columns": 12
      }
    },
    "unit": {
      "type": "object",
      "title": "Unit",
      "description": "foobar",
      "properties": {
        "symbol": {
          "type": "string",
          "description": "foobar"
        },
        "isPrefix": {
          "type": "boolean",
          "description": "foobar"
        }
      },
      "required": [
        "symbol",
        "isPrefix"
      ]
    },
    "dependsOn": {
      "type": "object",
      "title": "Dependencies",
      "options": {
        "collapsed": true
      },
      "description": "foobar",
      "properties": {
        "forData": {
          "type": "array",
          "items": {
            "type": "string"
          },
          "description": "foobar"
        }
      },
      "required": [
        "forData"
      ]
    },
    "nonEmptyOrWhiteSpaceString": {
      "type": "string",
      "minLength": 1,
      "pattern": ".*\\S.*"
    },
    "componentDisabledForScenes": {
      "title": "Disabled for Scenes",
      "description": "foobar",
      "type": "boolean",
      "format": "checkbox"
    },
    "componentDisabledForFilters": {
      "title": "Disabled for Filters",
      "description": "foobar",
      "type": "boolean",
      "format": "checkbox"
    },
    "filterDisabledForScenes": {
      "title": "Disabled for Scenes",
      "description": "foobar",
      "type": "boolean",
      "format": "checkbox"
    },
    "filterDisabledForFilters": {
      "title": "Disabled for Filters",
      "description": "foobar",
      "type": "boolean",
      "format": "checkbox"
    }
  }
}

JSON

Sample JSON Content
{
  "$schema": "foobar",
  "edw": {
    "connectionString": "foobar",
    "commandTimeout": 300
  },
  "uiSettings": {
    "title": "foobar",
    "logo": {
      "base64": "foobar"
    }
  },
  "grains": [
    {
      "grainKey": "foobar",
      "entityName": "foobar",
      "entityIdField": "foobar",
      "results": {
        "columns": [
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": false
          },
          {
            "title": "foobar",
            "column": "foobar",
            "includeInSearch": true,
            "alias": "foobar"
          }
        ]
      },
      "uiName": {
        "singular": "foobar",
        "plural": "foobar"
      },
      "filterTypes": [
        {
          "isMainGrain": true,
          "uiIndex": 0,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": true,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": true,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": true,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": true,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar",
                "foobar",
                "foobar",
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 1,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 2,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "isMacro": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "comments": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 3,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 4,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterCriteria": [],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "dependsOn": {
                  "forData": []
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MixedMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "numericName": "foobar",
                "textName": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "textValueSelector": "foobar",
                "numberValueSelector": "foobar",
                "dependsOn": {
                  "forData": [
                    "foobar"
                  ]
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 5,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 6,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterCriteria": [],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "dependsOn": {
                  "forData": []
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "comments": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar",
                "dependsOn": {
                  "forData": []
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 7,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 8,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterCriteria": [
            "foobar"
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "Registry",
              "uiConfig": {
                "name": "foobar",
                "placeholderText": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 9,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "Select",
              "uiConfig": {
                "name": "foobar",
                "placeholderText": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "NumberRange",
              "uiConfig": {
                "name": "foobar",
                "unit": {
                  "symbol": "foobar",
                  "isPrefix": false
                }
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 10,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MixedMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "numericName": "foobar",
                "textName": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "comments": "foobar",
                "textValueSelector": "foobar",
                "numberValueSelector": "foobar",
                "dependsOn": {
                  "forData": [
                    "foobar"
                  ]
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 11,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "isMacro": true
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        }
      ]
    },
    {
      "grainKey": "foobar",
      "entityName": "foobar",
      "entityIdField": "foobar",
      "results": {
        "columns": [
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          }
        ]
      },
      "uiName": {
        "singular": "foobar",
        "plural": "foobar"
      },
      "filterTypes": [
        {
          "isMainGrain": false,
          "uiIndex": 0,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar",
                "foobar",
                "foobar",
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 1,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 2,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "isMacro": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "comments": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 3,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ],
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 4,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterCriteria": [],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "dependsOn": {
                  "forData": []
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MixedMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "numericName": "foobar",
                "textName": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "textValueSelector": "foobar",
                "numberValueSelector": "foobar",
                "dependsOn": {
                  "forData": [
                    "foobar"
                  ]
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 5,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 6,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterCriteria": [],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "dependsOn": {
                  "forData": []
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "comments": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar",
                "dependsOn": {
                  "forData": []
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 7,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 8,
          "name": "foobar",

          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterCriteria": [
            "foobar"
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "Registry",
              "uiConfig": {
                "name": "foobar",
                "placeholderText": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 10,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MixedMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "numericName": "foobar",
                "textName": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "comments": "foobar",
                "textValueSelector": "foobar",
                "numberValueSelector": "foobar",
                "dependsOn": {
                  "forData": [
                    "foobar"
                  ]
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        }
      ]
    },
    {
      "grainKey": "foobar",
      "entityName": "foobar",
      "entityIdField": "foobar",
      "results": {
        "columns": [
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          },
          {
            "title": "foobar",
            "column": "foobar",
            "alias": "foobar",
            "includeInSearch": true
          }
        ]
      },
      "uiName": {
        "singular": "foobar",
        "plural": "foobar"
      },
      "filterTypes": [
        {
          "isMainGrain": false,
          "uiIndex": 0,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar",
                "foobar",
                "foobar",
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 1,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 2,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "isMacro": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "comments": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 3,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ],
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 4,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterCriteria": [],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "dependsOn": {
                  "forData": []
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MixedMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "numericName": "foobar",
                "textName": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "textValueSelector": "foobar",
                "numberValueSelector": "foobar",
                "dependsOn": {
                  "forData": [
                    "foobar"
                  ]
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 5,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 6,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterCriteria": [],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                },
                "dependsOn": {
                  "forData": []
                },
                "comments": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false,
                "isMacro": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "comments": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar",
                "dependsOn": {
                  "forData": []
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                },
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 7,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "comments": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "ValueSetMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": true,
                "allowCSV": true,
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "valueSetCodeCriteria": [
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  },
                  {
                    "comments": "foobar",
                    "codeSystemGuid": "foobar"
                  }
                ]
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "aggregates": {
            "count": {
              "enabled": true,
              "distinctFieldOptions": [
                {
                  "key": "foobar",
                  "title": "foobar",
                  "fieldName": "foobar"
                }
              ]
            }
          },
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 8,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            }
          ],
          "filterCriteria": [
            "foobar"
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "Registry",
              "uiConfig": {
                "name": "foobar",
                "placeholderText": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        },
        {
          "isMainGrain": false,
          "uiIndex": 10,
          "name": "foobar",
          "filterTypeKey": "foobar",
          "helpText": "foobar",
          "filterJoins": [
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar"
            },
            {
              "joinTargetName": "foobar",
              "joinIdField": "foobar",
              "sourceIdField": "foobar"
            }
          ],
          "filterComponents": [
            {
              "filterComponentKey": "foobar",
              "typeKey": "MultiSelect",
              "uiConfig": {
                "name": "foobar",
                "codeIsSignificant": false,
                "allowCSV": false
              },
              "config": {
                "valueSelector": "foobar",
                "selectOptions": {
                  "comments": "foobar",
                  "table": "foobar",
                  "codeSelector": "foobar",
                  "titleSelector": "foobar"
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "TemporalConstraint",
              "uiConfig": {
                "name": "foobar",
                "displayMode": "foobar"
              },
              "config": {
                "dateSelector": "foobar"
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            },
            {
              "filterComponentKey": "foobar",
              "typeKey": "MixedMultiSelect",
              "uiConfig": {
                "name": "foobar",
                "numericName": "foobar",
                "textName": "foobar",
                "comments": "foobar",
                "helpText": "foobar"
              },
              "config": {
                "comments": "foobar",
                "textValueSelector": "foobar",
                "numberValueSelector": "foobar",
                "dependsOn": {
                  "forData": [
                    "foobar"
                  ]
                }
              },
              "disabledForScenes": false,
              "disabledForFilters": false
            }
          ],
          "uiFilterComponentGroups": [
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar",
                "foobar"
              ]
            },
            {
              "label": "foobar",
              "filterComponentKeys": [
                "foobar"
              ]
            }
          ],
          "disabledForScenes": false,
          "disabledForFilters": false
        }
      ]
    }
  ],
  "valueSetSettings": {
    "enabled": false,
    "terminologyUrl": "foobar",
    "authorityDescription": "foobar",
    "clientCode": "foobar"
  }
}
@pmk65
Copy link
Collaborator

pmk65 commented Dec 21, 2018

@j2jensen Have you checked the Wiki? There's a section named Handle Large Arrays with the JSON editor

@j2jensen
Copy link
Contributor Author

I have looked at the Wiki a few times. I'd never noticed that page, but I took some time to look it over. The link to the class it mentions is broken, and to be honest it doesn't really make sense to me. Have you read through it?

@pmk65
Copy link
Collaborator

pmk65 commented Dec 22, 2018

@j2jensen Try here: https://github.com/niebert/Editor4JSON and here: https://github.com/niebert/json-editor-dorn
I know that @niebert is a very competent contributor/user of JSON-Editor. So I have no doubt that it is working.

@j2jensen
Copy link
Contributor Author

j2jensen commented Dec 22, 2018 via email

@pmk65
Copy link
Collaborator

pmk65 commented Dec 22, 2018

@j2jensen Note: The fork of JSON-Editor at @niebert, is a fork of the original jdorn version of JSON-Editor.
That version lacks several of the new features available in this fork.

I have updated the links on the Wiki page.

BTW: Do you have Danish ancestors? As your surname is a typical Danish surname.
(I'm from Denmark myself, but people expect me to be German due to my surname. 🤣 )

@j2jensen
Copy link
Contributor Author

j2jensen commented Dec 22, 2018 via email

@j2jensen
Copy link
Contributor Author

All right, I was able to take a look at what he's doing, and I understand it. It's not quite the same problem we're running into, because instead of having hundreds of simple items in one big top-level array, we've got a complex nested structure. There's at most a dozen elements in any given array, but it adds up to hundreds of overall array elements and thousands of nodes once you traverse the entire tree.

If necessary, we could probably rearrange our schema so that the top-level properties can be edited as part of one object and the "filter grains" can be selected from a list and edited independently. I think any individual grain would probably be small enough that it could be loaded in an editor without timing out the browser. But that feels a bit like a work-around for something that the editor itself seems well-situated to handle by itself.

If you use the schema and json that I've posted in the interactive demo, you can see that I'm using tab formatting for various array types (grains, columns, filters, and filter components), so most of the UI elements that get generated never actually get rendered in the browser. If those tabs' contents could be generated on-demand the first time the tab is opened rather than all getting generated when the editor is first initialized, it would be vastly faster.

Of course, I haven't dug through the json-editor code enough to understand whether this would actually be anywhere near as simple as it sounds. I know things like this are never as easy as they seem, and I don't want to be that guy that says, "Can't you just...?" But I thought I'd mention that the time taken to generate all the DOM is impacting us, and if there's any way to solve that within the editor itself that would be fantastic.

@pmk65
Copy link
Collaborator

pmk65 commented Dec 23, 2018

@j2jensen The tabs/categories are handled by the object editor (editors/object.js) and it currently has some unresolved issues (see #214)
One of the problems is that it adds a lot of unnecessary nested wrappings around each input, which might be the cause of some of the slowdown. There's a PR #243 fixing that issue. You could try pulling it and see if that helps in any way.

I think building the form dynamically upon expanding would require major changes, but you can create/extend your own custom object editor if you feel up for the task. 😉

@j2jensen
Copy link
Contributor Author

j2jensen commented Dec 24, 2018

I checked out that PR's code, and it doesn't seem to make much of a difference, which doesn't surprise me. Profiling performance, it appears that 25-30% of our time is spent in the setButtonText method (the one in theme.js).

  setButtonText: function(button, text, icon, title) {
    button.innerHTML = '';
    if(icon) {
      button.appendChild(icon);
      button.innerHTML += ' ';
    }
    button.appendChild(document.createTextNode(text));
    if(title) button.setAttribute('title',title);
  }

The most likely source for trouble in this method is button.innerHTML += ' ';. Commenting that line out, setButtonText is no longer among the worst culprits, so if we can fix the method to avoid that pattern we'd likely have a quick win. However, even without that particular hot-spot, rendering takes several seconds on my machine, with the bottom-up time split between the following activities:

Self Time Total Time Activity  
1496.7 ms13.8 % appendChild  
891.0 ms8.2 % 891.0 ms8.2 % DOM GC  
619.1 ms5.7 % 1010.5 ms9.3 % $extendutilities.js:25  
617.6 ms5.7 % 898.4 ms8.3 % setSelectOptions
520.4 ms4.8 % 520.4 ms4.8 % Major GC  
448.3 ms4.1 % 505.2 ms4.7 % getTabHolderbootstrap2.js:172  
370.7 ms3.4 % 961.6 ms8.9 % getDescriptiontheme.js:236  
341.9 ms3.2 % 350.2 ms3.2 % requestAnimationFrame  
320.0 ms3.0 % 321.1 ms3.0 % createElement  
299.1 ms2.8 % 310.4 ms2.9 % add

We could spend some time digging into some of these activities to see if their speed can be improved, but even if we got all their time down to practically zero, that only accounts for about half of the overall time spent. And to be honest, there's probably not much we can do about things like appendChild and garbage collection. So finding some way to build out less DOM in the first place is probably going to be our best bet. It'll probably be too hard, but I'll dig into the code over the next week or two and see if inspiration strikes me.

@pmk65
Copy link
Collaborator

pmk65 commented Dec 24, 2018

We could probably improve the speed of DOM creation by using document fragment instead of applying directly to DOM. As fragment does not create reflows (repainting the page) when you add/delete a node.
https://developer.mozilla.org/en-US/docs/Web/API/DocumentFragment

Currently, each editor manipulates the DOM to insert/remove the HTML code. So to be effective, we will have to change that so they only manipulate the fragment. And then when all editors are done rendering the HTML, insert the fragment into the DOM.

Here are some jsperf tests that show the speed difference:
https://jsperf.com/docfragment-test
https://jsperf.com/document-fragment-test-peluchetti/38
https://jsperf.com/document-fragment-test-peluchetti

@j2jensen
Copy link
Contributor Author

Are you specifically talking about using document fragments in setButtonText to avoid the innerHtml += ... pattern? Or are you talking about changing the way the editor builds out the DOM generally?

If the former, then I don't think that's really necessary. Since we're creating a text node to add to the button anyway, I'm pretty sure something like this would be simpler and faster than using a document fragment:

  setButtonText: function(button, text, icon, title) {
    // Clear previous contents. https://jsperf.com/innerhtml-vs-removechild/37
    while (button.firstChild) {
      button.removeChild(button.firstChild);
    }
    if(icon) {
      button.appendChild(icon);
      text = ' ' + text;
    }
    button.appendChild(document.createTextNode(text));
    if(title) button.setAttribute('title',title);
  }

If the latter, then it probably depends. I get the impression that working with a document fragment is pretty similar to working with any element that hasn't been added to the document yet. The last link you provided, for example, shows that using a document fragment is actually slower if you were just building DOM elements anyway. I've been working under the assumption that the JSON Editor DOM is all built in-memory and only added to the document once everything is built. If that's not the case then we probably could see a significant performance boost by doing so, regardless of whether we use documentFragment.

Regarding the original approach I'd suggested, I notice that when we use oneOf in the schema, the JSON Editor uses a select box to show the different options, and appears to build the DOM on-demand when the select option changes. So that implies that the pattern of lazily building the DOM in response to an event already exists in the library. Seems like we could leverage that. I still need to dig into the code some more though.

@pmk65
Copy link
Collaborator

pmk65 commented Dec 28, 2018

If the latter, then it probably depends. I get the impression that working with a document fragment is pretty similar to working with any element that hasn't been added to the document yet. The last link you provided, for example, shows that using a document fragment is actually slower if you were just building DOM elements anyway.

Yes. Doing simple stuff like the last test example, won't help speed up the rendering. Only if all editors push elements to fragment and then at the end the fragment is inserted. But I'm not sure if it is possible without a major rewrite.

Using innerHTML could be one of the culprits of the slow DOM creation. So maybe we should look at changing all occurrences of that? InnerHTML Test

Regarding the original approach I'd suggested, I notice that when we use oneOf in the schema, the JSON Editor uses a select box to show the different options, and appears to build the DOM on-demand when the select option changes. So that implies that the pattern of lazily building the DOM in response to an event already exists in the library. Seems like we could leverage that. I still need to dig into the code some more though.

Each editor inserts code when called. Some editors (like Array and Object), triggers the editor when you click the button/select box.

@j2jensen
Copy link
Contributor Author

j2jensen commented Dec 28, 2018

Only if all editors push elements to fragment and then at the end the fragment is inserted.

Even this wouldn't actually have much of an impact. As this test shows, adding elements to a DOM element which is detached from the document body is every bit as fast as using an HTML Fragment. Since that's largely what the editor does already, using HTML fragments won't change much. So that approach is a red herring.

Likewise, since innerHTML is vastly slower than other approaches, it's easy to suppose that we can improve performance a lot by not using it. But the InnerHTML Test you linked shows that even though it's roughly 40x as slow as the alternative, it can still run 100,000 times in 100 milliseconds. And a perf test using chrome's dev tools doesn't appear to indicate that we're spending lots of time in innerHTML.

We should forget about small efficiencies, say about 97% of the time: premature optimization is the root of all evil. Yet we should not pass up our opportunities in that critical 3%."
Donald Knuth: http://wiki.c2.com/?PrematureOptimization

Looking at what's actually causing poor performance, the single biggest issue that jumps out to me is that we're taking the time to build out the entire DOM before allowing user interaction, even though (in a schema like mine) only 2% of it is even going to be seen. Addressing any of the other issues is likely to shave off maybe a hundred milliseconds here or there, but if we simply limit our focus to creating the elements that actually get rendered, we'll make the user experience practically instantaneous.

@j2jensen
Copy link
Contributor Author

I've been tinkering with the code, and I think I see a good way forward. Here's what I'm thinking:

When the Array editor is initializing its rows, if it's set up to use tabs it can keep track of what the row's value should be, without actually building out that row; we'll say that this row is "deferred".

  • Anywhere we're currently calling setValue on an individual row, we can instead call a new setRowValue method, which either calls setValue or sets the deferred value, depending on whether that row's construction is being deferred.

  • Anywhere we currently say self.value[i] = editor.getValue(), we'll instead call a new refreshRowValue method, which either pulls from the deferred value or editor.getValue() depending on whether the row's construction is being deferred.

  • When refreshTabs detects the active row, it can check to see if that row has a "deferred" value and (if so) build it out and set its value, at which point the "deferred" flag is removed.

This makes the initial load much faster. Setting up the editor is no longer the bottleneck: now validation is the biggest performance bottleneck. However, since each tab's contents are initialized once it's selected, and since setting an editor's value causes validation to get kicked off, that validation cost is incurred each time a new tab is selected. To mitigate this, I'm planning to change core.js to cache the most recently-validated json and only call validator.validate if the validated json has changed.

The only snag that I've identified in this plan is that the tab headers are currently populated by asking the row's editor for its header text. If we haven't initialized the editor yet, then we can't expect to get the text that way. I imagine I'll find a way to make this work, but I haven't yet and I'd be open to any suggestions.

I would also love any other input or warnings you'd have about this approach. Are there corner cases I need to watch out for that I might not be thinking about? Would you accept a pull request that takes this approach? Should this deferred loading of tab contents be some kind of configurable option? If so, should it be configured editor-wide or in the schema itself? Should it be enabled or disabled by default?

@pmk65
Copy link
Collaborator

pmk65 commented Jan 1, 2019

There are a couple things you might want to test.

  1. Does watched fields work using the 'deferred' approach?
  2. Return value. Does this include fields from 'deferred' tabs?

If you can implement this new feature so setup/usage is identical to before, I see no reason to add a config option. Only if the setup/usage differs there's a need to be able to turn the feature on/off.

@Fluf22
Copy link

Fluf22 commented Jan 9, 2019

Hey!
Coming from my duplicate #263 (sorry about that!)
I had the same problem at work, and I had to come up with a quick fix to handle the large arrays we were dealing with.
I think it is very close to what you say @j2jensen !
When there is no specified format, the array is initialized as usual. But if you use format: "tabs" or format: "tabs-top", it only loads the displayed item.
All of the other items store their data in a legacy_value property. When refreshValue or setValue is clicked, it uses legacy_value if value isn't set. Then, it's set it, and delete legacy_value to avoid data mismatch.
We used this fix during the past few months, and only saw one downside: it prevents the use of the watch keyword, since the data are not really loaded. But I may not have digged enough in the code to find a solution about that.

If I'm not clear enough, tell me and I'll try to explain myself better ;)

Thanks,
Thomas

@pmk65
Copy link
Collaborator

pmk65 commented Jan 9, 2019

I just updated the links to the CDN files, So if you have been using CDN links in your tests, you need to update the link to the new format. (See the docs page)
The CDN link was linking to an old 1.2.1 release, not the newest version.

@j2jensen
Copy link
Contributor Author

j2jensen commented Jan 9, 2019

@Fluf22 thanks for adding to the discussion. I've pushed my first stab at this to a branch on my fork: https://github.com/j2jensen/json-editor/tree/performance-improvements

My current approach doesn't load the headers correctly. I'd like to see your changes and compare notes.

I haven't had a chance to check how my branch behaves with watches. Supposing it interferes with watch behavior, though, that's probably something that should involve a little discussion here. It seems like we might be able to make watches work by handling them at a high level and using the current editor paths to figure out which handlers to invoke when an event is fired (kind of like jQuery's parent.on(events, selector, handler) pattern). But if someone added a watch for items.0 and then it got reordered to become items.1 then the handler originally associated with items.1 would get invoked when the item was changed--not the handler for items.0. This could actually be preferred behavior for some people--these kinds of ambiguities make adding watches to individual array items a pretty weird use case, which is why it's been discouraged in the past. But it would be a breaking change for anyone relying on the previous behavior.

Alternatively, we could make the deferred loading configurable and opt-in (either editor-wide or as an option on specific schema elements), and add documentation stating this is a good way to improve loading performance but it'll prevent watches from working on array elements.

I have a deadline coming up for some unrelated work so I probably can't spend much time on this for the next few weeks, but I would like to see a resolution to this maybe some time in February.

@Fluf22
Copy link

Fluf22 commented Jan 10, 2019

@j2jensen I looked at your code (but didn't test it), and asked myself a question. When I tried to improve the performance on my side, I stumbled upon some edge cases, like value refresh when adding / deleting / copying / moving items. Don't you had the same issues ? Because your code is much more clearer than mine!
I just uploaded my code, if you have some time, please check this commit on my fork : https://github.com/Fluf22/json-editor/commit/17c60597b7da698da129223f46818c88db8d851a
EDIT: ...this commit https://github.com/Fluf22/json-editor/compare/a86ba7f..ea28b98
And don't hesitate to tell me what you think about it ;)

Thanks,
Thomas

@j2jensen
Copy link
Contributor Author

@Fluf22 Since I've only had a few hours to work on this, I haven't had a chance to run into those edge cases yet. Playing with my solution now, it does look like there's some weirdness when adding an item, but copying, moving, and deleting all seem to work fine. When I have time later in the month I'll look into a way to fix adding an item, as well as looking over your changes. I would love to hear about any other edge cases that you found to be problematic, to make sure we address those.

@Fluf22
Copy link

Fluf22 commented Jan 10, 2019

@j2jensen Okay, let me know when you have time to work on it.
Apart from item edition, I had to check that headers stay updated, and I didn't take time to fix the watch keyword, for now.
And there is still improvments possible, since the editor go slow again when I activate too much items.

@j2jensen
Copy link
Contributor Author

Update: we've discovered that in our case, even though the editor does take a long time to load (10+ seconds), what was actually making it crash the browser for some users was when they had the LastPass extension installed. I'm not sure if LastPass just started taking a long time to scan the fields to try to determine if they're for a form, or if we hit on some corner case that threw it into an infinite loop, or what.

I've logged an issue with LastPass to see if there's any way to simply prevent it from trying to scan our site in the first place. In the meantime, we'll just have to make sure the handful of users that access the page where we use this editor are instructed to disable the extension for our site.

Knowing that the real issue for us was more related to that plugin than to the editor's actual performance, there's a chance that this will not take priority for me, although I would like to pick it up again if I can find any "spare time".

@taschmidt
Copy link

@j2jensen I know it's probably a long shot, but did you ever get any resolution with LastPass? We encountered the same thing, those with LastPass installed see SIGNIFICANT delays (like 4-5x)!

@j2jensen
Copy link
Contributor Author

No real resolution, no. They pointed me to this FAQ, which I was already aware of: https://lastpass.com/support.php?cmd=showfaq&id=10512

To prevent LastPass icons on your website or application from appearing on non-desired fields, add 'data-lpignore'=true attribute to your form fields, this will prevent LastPass icons from being generated in this particular locations.

Thing is, we're not trying to prevent them from adding their lastpass icons: we're trying to prevent them from scanning the DOM in the first place. I haven't tested adding this attribute to all the text boxes, but I doubt it'll address the problem.

It wouldn't hurt to have more people log issues with LastPass. Maybe it'll draw more attention to the issue for them.

@pmk65
Copy link
Collaborator

pmk65 commented Feb 19, 2019

I'm not familiar with Lastpass myself, but from the link @j2jensen posted, it looks like it inserts some kind of icon for each form field. It that's the case, the data-lpignore might help. As inserting icons into the DOM for every form field take a lot of time. Specially if they do it one-by-one.
(You can add custom attributes to the input tags using the inputAttributes option.)

@Fluf22
Copy link

Fluf22 commented Jun 17, 2019

Hey everyone!
I'm upping this topic since it's still something I would like to help improving :)
I'm working with it since january, and no issue seems to have been found.
What are your thoughts about this, @pmk65 @j2jensen ?

Thanks,
Thomas

@pmk65
Copy link
Collaborator

pmk65 commented Jun 17, 2019

Hey everyone!
I'm upping this topic since it's still something I would like to help improving :)
I'm working with it since january, and no issue seems to have been found.
What are your thoughts about this, @pmk65 @j2jensen ?

Thanks,
Thomas

@Fluf22 It would be nice if we could make a speed comparison test between the main branch and yours.
I know that @schmunk42 and @germanbisurgi has a lot more experience in writing tests than me, so maybe they could whip up something?

Or have you made some tests yourself?

@pmk65 pmk65 assigned pmk65 and unassigned pmk65 Jun 17, 2019
@Fluf22
Copy link

Fluf22 commented Jun 17, 2019

Actually, I work with very large JSON objects everyday, but my company won't let me give them to you as tests 😀
I will try to come up with some explicit tests later (except if someone want to write a 1Mb / 23000 lines JSON object for me 😛 )

@j2jensen
Copy link
Contributor Author

Can you use the schema/json I posted and just duplicate the top-level objects until you get to an object that's the size you need?

For my part, my team has plans to start breaking down the objects we're dealing with into smaller pieces anyway, for reasons other than the performance of this editor. So it probably won't be a high priority for me to engage with it. However, I'll have some time off on the first week of July so I might jump into it for a bit then for fun if it looks like we might have a promising path forward.

@pmk65
Copy link
Collaborator

pmk65 commented Jun 17, 2019

@Fluf22 did you solve the issues with watch, that you mentioned earlier?

@Fluf22
Copy link

Fluf22 commented Jun 21, 2019

@pmk65 Not yet, sadly! I didn't get the time, but I may be able to dive into it again, soon. Perhaps mid-july.

@robocoder
Copy link
Contributor

@milahu

This comment has been minimized.

@j2jensen
Copy link
Contributor Author

@milahu Done. Thanks for teaching me about that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants