{"id":44952,"date":"2026-06-07T16:52:03","date_gmt":"2026-06-07T14:52:03","guid":{"rendered":"https:\/\/www.dbi-services.com\/blog\/?p=44952"},"modified":"2026-06-07T16:52:05","modified_gmt":"2026-06-07T14:52:05","slug":"m-files-bd-anatomy-of-a-dashboard-definition","status":"publish","type":"post","link":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/","title":{"rendered":"M-Files BD &#8211; Anatomy of a dashboard definition"},"content":{"rendered":"\n<p>In the <a href=\"https:\/\/www.dbi-services.com\/blog\/m-files-bd-end-user-experience\/\" id=\"44932\" target=\"_blank\" rel=\"noreferrer noopener\">previous post<\/a>, I walked through what an end user sees when they open the Business Dashboard pane in M-Files. From this post on, the audience shifts more towards the administrator&#8217;s side, looking at how a dashboard is actually defined.<\/p>\n\n\n\n<p>Every dashboard is a single JSON document. The Admin tab in M-Files Admin offers a Visual Designer that builds this JSON for you, but in the end the JSON is the source of truth, so I think it is worth understanding its shape before getting into widget types and queries in the next posts. Think of this post as the <strong>reference map<\/strong> the rest of the series will refer back to.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-1-the-minimum-valid-dashboard\">1. The minimum valid dashboard<\/h2>\n\n\n\n<p>Before discussing every field, here is the (almost) smallest dashboard JSON that the engine accepts. It is intentionally trivial &#8211; a single KPI widget counting all Documents in the vault:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n{\n  &quot;schemaVersion&quot;: 1,\n  &quot;id&quot;: &quot;&quot;,\n  &quot;name&quot;: &quot;My Dashboard&quot;,\n  &quot;widgets&quot;: &#x5B;\n    {\n      &quot;id&quot;: &quot;&quot;,\n      &quot;title&quot;: &quot;Total Documents&quot;,\n      &quot;type&quot;: &quot;kpiNumber&quot;,\n      &quot;query&quot;: {\n        &quot;objectType&quot;: &quot;Document&quot;,\n        &quot;aggregation&quot;: { &quot;type&quot;: &quot;summary&quot; }\n      }\n    }\n  ]\n}\n<\/pre><\/div>\n\n\n<p><strong>Note 1:<\/strong> Boolean-like fields are exposed as the strings <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong>. This is what M-Files shows as booleans, don&#8217;t ask me why it&#8217;s not True\/False like the rest of the world ;).<\/p>\n\n\n\n<p><strong>Note 2:<\/strong> Display names (object types, classes, properties, value-list items) must match what the vault shows in M-Files Admin. They are case-insensitive but must otherwise be exact.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-2-the-dashboard-level-fields\">2. The dashboard-level fields<\/h2>\n\n\n\n<p>The top-level object can carry the following fields: required ones are marked, all others are optional with default values that make sense, usually.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-1-identification-and-presentation\">2.1. Identification and presentation<\/h3>\n\n\n\n<p>These are the main parameters of a dashboard that you will usually set at the beginning:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>schemaVersion<\/em><\/strong>: Integer (currently <strong><em>1<\/em><\/strong>). The <strong>Business Dashboard<\/strong> validation process emits a warning when this field is absent or lower than expected. This version is incremented when breaking changes are introduced, so admins will automatically be flagged that they need to update something.<\/li>\n\n\n\n<li><strong><em>id<\/em><\/strong> <em>(required)<\/em>: typically a UUID v4 value (e.g. <strong><em>&#8220;12345678-abcd-1234-5678-abcd12345678&#8221;<\/em><\/strong>) but it isn&#8217;t restricted to that (e.g. <strong><em>&#8220;d01-contracts&#8221;<\/em><\/strong> works as well). The ID should be unique for each dashboard, otherwise you risk overriding an existing dashboard when you save. You can leave the field ID empty (as done above), the <strong>Business Dashboard<\/strong> will automatically generate one for you.<\/li>\n\n\n\n<li><strong><em>name<\/em><\/strong> <em>(required)<\/em>: Text shown in the end-user dropdown, you should keep it concise (&lt;250 chars).<\/li>\n\n\n\n<li><strong><em>description<\/em><\/strong>: Optional subtitle shown in italic below the top bar (hidden when absent). As described in the previous post, the first two lines will be shown on the user side, with a hover tooltip for the full text.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-2-auto-refresh\">2.2. Auto-refresh<\/h3>\n\n\n\n<p>These are parameters that controls whether or not the dashboard will refresh itself or allows controls about the refresh more globally:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>autoRefreshEnabled<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). Whether auto-refresh is enabled when the dashboard first loads.<\/li>\n\n\n\n<li><strong><em>autoRefreshIntervalSeconds<\/em><\/strong>: Integer (default <strong><em>300<\/em><\/strong>, minimum <strong><em>15<\/em><\/strong>). Typical values can be <strong><em>60<\/em><\/strong>, <strong><em>300<\/em><\/strong> or <strong><em>900<\/em><\/strong> for example. This is the interval of time between two auto-refresh of all widgets done when the auto-refresh is enabled (either via <strong><em>autoRefreshEnabled<\/em><\/strong> or because <strong><em>userCanToggleAutoRefresh<\/em><\/strong> is <strong><em>&#8220;Yes&#8221;<\/em><\/strong> and a user enabled it manually). The minimum is set to 15s to avoid overloading the vault in case of mis-configuration.<\/li>\n\n\n\n<li><strong><em>userCanToggleAutoRefresh<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). Whether the user can disable or enable the auto-refresh feature.<\/li>\n<\/ul>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-3-exports-and-drill-through\">2.3. Exports and drill-through<\/h3>\n\n\n\n<p>These are the optional features that you can enable:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>exportToPdfEnabled<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). Shows the \u2399 PDF button in the top bar, to allow users to export the dashboard to PDF.<\/li>\n\n\n\n<li><strong><em>exportToCsvEnabled<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). Shows the \u229e CSV button on all widgets (except kpiNumber &amp; gauge) as well as on the drill-through modal, to allow users to export the widget details to CSV.<\/li>\n\n\n\n<li><strong><em>drillThroughEnabled<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). Makes chart elements and rows clickable to open the drill-through modal (c.f. previous post if you don&#8217;t know what the drill-through is).<\/li>\n<\/ul>\n\n\n\n<p>These three flags are intentionally off by default. Turning them on is an explicit choice per dashboard, which I think is the right place to make that decision. A dashboard meant for casual &#8220;at-a-glance&#8221; use might not need them while a dashboard meant for active investigation might.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-4-performance-settings\">2.4. Performance settings<\/h3>\n\n\n\n<p>These are security and performance settings:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>skipTemplateCheck<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). When <strong><em>&#8220;No&#8221;<\/em><\/strong> (default), objects marked as template (i.e. they have the &#8220;is Template&#8221; property and it is checked) are automatically excluded from any results. When <strong><em>&#8220;Yes&#8221;<\/em><\/strong>, this additional verification is skipped and templates can therefore be part of the results (faster execution).<\/li>\n\n\n\n<li><strong><em>skipObjectPermissionCheck<\/em><\/strong>: <strong><em>&#8220;Yes&#8221;<\/em><\/strong> or <strong><em>&#8220;No&#8221;<\/em><\/strong> (default <strong><em>&#8220;No&#8221;<\/em><\/strong>). When <strong><em>&#8220;No&#8221;<\/em><\/strong> (default), every queries will respect the user-level accesses \/ ACLs, so different users might see different results \/ numbers \/ lists of objects, depending on their permissions. When <strong><em>&#8220;Yes&#8221;<\/em><\/strong>, server-level accesses are used, so different users will see the same results, always (faster execution).<\/li>\n\n\n\n<li><strong><em>serverScanMaxResults<\/em><\/strong>: Integer (default <strong><em>500<\/em><\/strong>). The maximum number of M-Files objects fetched per widget query. You can set it to <strong><em>0<\/em><\/strong> for unlimited.<\/li>\n\n\n\n<li><strong><em>drillThroughMaxResults<\/em><\/strong>: Integer (default <strong><em>300<\/em><\/strong>). Maximum rows shown in drill-through modals and <strong><em>list<\/em><\/strong> tables. You can set it to <strong><em>0<\/em><\/strong> for unlimited. The pagination for the opened modal is set at 15 rows per page. Therefore, there can be up to 20 pages by default.<\/li>\n<\/ul>\n\n\n\n<p>I will dedicate a full post (Post 8 in the series) to these details and to the trade-offs they imply, so I will not spend too much time on them here. The defaults are reasonable for most use-cases but you can change everything, of course.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-5-access-control\">2.5. Access control<\/h3>\n\n\n\n<p>Finally, the last parameter is about access control to the dashboard:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>assignedTo<\/em><\/strong>: An object with two optional arrays, <strong><em>users<\/em><\/strong> and <strong><em>groups<\/em><\/strong>. When the arrays are absent or empty, the dashboard is public. This means that ANY M-Files user will be able to select the dashboard from the dropdown. It does NOT mean that he will see something inside the widgets! Therefore, it gives access to the dashboard itself, but widget content still relies on the user&#8217;s ACLs by default (or server-level access if <strong><em>skipObjectPermissionCheck<\/em><\/strong> is set to <strong><em>&#8220;Yes&#8221;<\/em><\/strong>, c.f. above section). On the other hand, when at least one of the arrays is present, access is granted to any user who appears in the <strong><em>users<\/em><\/strong> array <strong>OR<\/strong> is a member of any group in the <strong><em>groups<\/em><\/strong> array.<\/li>\n<\/ul>\n\n\n\n<p>In this example, the dashboard will be accessible by the user whose Login Account is <strong><em>Morgan.Patou<\/em><\/strong> OR any users part of the <strong><em>Finance Team<\/em><\/strong> OR <strong><em>Management<\/em><\/strong> groups:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n&quot;assignedTo&quot;: {\n  &quot;users&quot;: &#x5B;&quot;Morgan.Patou&quot;],\n  &quot;groups&quot;: &#x5B;&quot;Finance Team&quot;, &quot;Management&quot;]\n}\n<\/pre><\/div>\n\n\n<h3 class=\"wp-block-heading\" id=\"h-2-6-widgets\">2.6. Widgets<\/h3>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>widgets<\/em><\/strong> <em>(required)<\/em>: An array of widget objects. The order in this array is the order they appear on the grid. The size of the widget (column span, row span) is part of each widget&#8217;s definition (i.e. inside the array).<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-3-the-widget-object\">3. The widget object<\/h2>\n\n\n\n<p>Each entry in the <strong><em>widgets<\/em><\/strong> array has the following shape:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n{\n  &quot;id&quot;: &quot;&quot;,\n  &quot;title&quot;: &quot;My Widget&quot;,\n  &quot;description&quot;: &quot;An example description for My Widget&quot;,\n  &quot;type&quot;: &quot;kpiNumber&quot;,\n  &quot;gridColumnSpan&quot;: 3,\n  &quot;gridRowSpan&quot;: 1,\n  &quot;query&quot;: { ... },\n  &quot;display&quot;: { ... }\n}\n<\/pre><\/div>\n\n\n<p>Here is a quick description of the different fields:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong><em>id<\/em><\/strong> <em>(required)<\/em>:  Same description as for the dashboard<\/li>\n\n\n\n<li><strong><em>title<\/em><\/strong> <em>(required)<\/em>:  Name of the widget shown at the top of the tile<\/li>\n\n\n\n<li><strong><em>description<\/em><\/strong>: Optional one-line italic subtitle just below the title. Annotate what the widget measures, or flag a caveat<\/li>\n\n\n\n<li><strong><em>type<\/em><\/strong> <em>(required)<\/em>:  One of <strong><em>kpiNumber<\/em><\/strong>, <strong><em>gauge<\/em><\/strong>, <strong><em>donut<\/em><\/strong>, <strong><em>bar<\/em><\/strong>, <strong><em>line<\/em><\/strong>, <strong><em>area<\/em><\/strong>, <strong><em>table<\/em><\/strong> (covered in posts 4a, 4b, 4c)<\/li>\n\n\n\n<li><strong><em>gridColumnSpan<\/em><\/strong>: Integer from 1 to 12 (default <strong><em>4<\/em><\/strong>). Represent the width of the widget on the dashboard<\/li>\n\n\n\n<li><strong><em>gridRowSpan<\/em><\/strong>: Integer (default <strong><em>1<\/em><\/strong>). Represent the height of the widget on the dashboard<\/li>\n\n\n\n<li><strong><em>query<\/em><\/strong> <em>(required)<\/em>:  The query the widget will execute. This can be pretty complex, so it will be detailed in Post 5 (filters) and Post 6 (aggregations), later<\/li>\n\n\n\n<li><strong><em>display<\/em><\/strong>: Type-specific display options, like color thresholds, unit, decimals, etc. It will be covered per widget type in posts 4a, 4b, 4c<\/li>\n<\/ul>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-4-the-query-object-in-one-paragraph\">4. The query object in one paragraph<\/h2>\n\n\n\n<p>As mentioned, the detailed walkthrough of queries is the topic of Post 5 \/ 6, but for completeness, here is the basic shape of a query:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n&quot;query&quot;: {\n  &quot;objectType&quot;: &quot;Document&quot;,\n  &quot;class&quot;: &quot;Contract or Agreement&quot;,\n  &quot;filters&quot;: &#x5B;\n    {\n      &quot;property&quot;: &quot;Effective through&quot;,\n      &quot;operator&quot;: &quot;greaterOrEqual&quot;,\n      &quot;value&quot;: &quot;@today&quot;,\n      &quot;valueType&quot;: &quot;dateToken&quot;\n    }\n  ],\n  &quot;aggregation&quot;: {\n    &quot;type&quot;: &quot;groupByProperty&quot;,\n    &quot;propertyName&quot;: &quot;Agreement type&quot;,\n    &quot;resolveValueListLabels&quot;: &quot;Yes&quot;,\n    &quot;includeEmptyResults&quot;: &quot;No&quot;\n  }\n}\n<\/pre><\/div>\n\n\n<p><strong><em>objectType<\/em><\/strong> can be a string or an array of strings (multi-object-type query). <strong><em>class<\/em><\/strong> is optional but strongly recommended for performance and to check only objects that actually matter&#8230; For example, you don&#8217;t need to fetch all documents (irrespective of their class) if you only want to count the number of active contracts. <strong><em>filters<\/em><\/strong> is an array of 1-to-N filter combined by <strong>AND<\/strong>. Finally, <strong><em>aggregation<\/em><\/strong> specifies the shape of the result and the reduction applied. To know more about these, please wait for the next posts.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-5-the-12-column-grid\">5. The 12-column grid<\/h2>\n\n\n\n<p>The layout is computed on a CSS grid with 12 columns. <strong><em>gridColumnSpan<\/em><\/strong> sets the width of a widget, while <strong><em>gridRowSpan<\/em><\/strong> sets its height in row units.<\/p>\n\n\n\n<p>Therefore, most common column layouts include:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li>4 widgets per row: <strong><em>gridColumnSpan: 3<\/em><\/strong> each. Typical for KPI tiles.<\/li>\n\n\n\n<li>3 widgets per row: <strong><em>gridColumnSpan: 4<\/em><\/strong> each. Medium tiles or narrow charts.<\/li>\n\n\n\n<li>2 widgets per row: <strong><em>gridColumnSpan: 6<\/em><\/strong> each. Charts and tables.<\/li>\n\n\n\n<li>1 widget per row: <strong><em>gridColumnSpan: 12<\/em><\/strong>. Full-width bar chart or wide table.<\/li>\n<\/ul>\n\n\n\n<p>These are just examples. Nothing prevents you to set 3 widgets on a row with <strong><em>gridColumnSpan: 5<\/em><\/strong>, <strong><em>gridColumnSpan: 4<\/em><\/strong>, <strong><em>gridColumnSpan: 3<\/em><\/strong> respectively. The Visual Designer is great for that since you get an exact view of what it will look like directly while creating the dashboard. More on that on the Post 9a.<\/p>\n\n\n\n<p>The widgets simply fill the rows from left to right in the order they appear in the <strong><em>widgets<\/em><\/strong> array, wrapping to the next row when a row&#8217;s spans sum exceeds 12. So planning the layout is largely a matter of ordering the widgets and giving each one a sensible column span.<\/p>\n\n\n\n<p>For row height, a small subtlety: <strong><em>gridRowSpan: 2<\/em><\/strong> does not give you exactly twice the canvas height of <strong><em>gridRowSpan: 1<\/em><\/strong>. It actually gives you roughly <strong>three times<\/strong> the canvas height, because each row unit subtracts a fixed overhead (header, padding, borders) from the available space. The practical consequence is that <strong>chart widgets<\/strong> (<strong><em>bar<\/em><\/strong>, <strong><em>line<\/em><\/strong>, <strong><em>area<\/em><\/strong>, <strong><em>donut<\/em><\/strong>, <strong><em>gauge<\/em><\/strong>) should almost always use <strong><em>gridRowSpan: 2<\/em><\/strong> or higher. A single-row chart has very little drawing space and ends up cramped.<\/p>\n\n\n\n<p>KPI number tiles, on the other hand, look fine at <strong><em>gridRowSpan: 1<\/em><\/strong> and that is the right default for them. As a rule of thumb: KPIs at 1, everything else at 2.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-6-where-the-definition-is-stored\">6. Where the definition is stored<\/h2>\n\n\n\n<p>Dashboard definitions are stored in the vault&#8217;s <strong>Named Value Storage<\/strong> (NVS). They are NOT stored as a specific object in the vault. I initially thought about creating them as standard vault objects but in the end decided the NVS would probably make it easier for deployments and usage in the long run. The trade-offs of that choice:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Pros<\/strong>: no extra object type to provision when installing the module, no ACL setup, no admin training on a new object type, no per-customer deployment friction. Backups of the vault include the dashboards automatically because NVS is part of the vault.<\/li>\n\n\n\n<li><strong>Cons<\/strong>: there is no per-definition version history of the kind you would get with vault objects. I mitigated this by offering Import and Export buttons in the Admin tab that produce <strong><em>.json<\/em><\/strong> files. What I would recommend is to manage those files in a Git repository, which gives a clean and conventional version history outside the vault, with diff support.<\/li>\n<\/ul>\n\n\n\n<p>The Export \/ Import buttons are the topic of Post 7. The TL;DR is that I would recommend that you should develop your dashboards on a DEV. Then, export them all into your git. Finally, when ready, import them into the TEST\/QA\/PROD environments, either manually or via CI\/CD pipelines.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-7-quick-overview-of-a-full-dashboard-json-definition\">7. Quick overview of a full dashboard JSON definition<\/h2>\n\n\n\n<p>Putting everything together, here is a slightly more complete (but still small) example. It has some of the dashboard-level fields modified from their default values to show-case actions and buttons, and two widgets:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\n{\n  &quot;schemaVersion&quot;: 1,\n  &quot;id&quot;: &quot;&quot;,\n  &quot;name&quot;: &quot;Contracts&quot;,\n  &quot;description&quot;: &quot;Quick overview of contracts&quot;,\n  &quot;autoRefreshEnabled&quot;: &quot;Yes&quot;,\n  &quot;autoRefreshIntervalSeconds&quot;: 60,\n  &quot;userCanToggleAutoRefresh&quot;: &quot;Yes&quot;,\n  &quot;exportToPdfEnabled&quot;: &quot;Yes&quot;,\n  &quot;exportToCsvEnabled&quot;: &quot;Yes&quot;,\n  &quot;skipTemplateCheck&quot;: &quot;No&quot;,\n  &quot;drillThroughEnabled&quot;: &quot;Yes&quot;,\n  &quot;skipObjectPermissionCheck&quot;: &quot;No&quot;,\n  &quot;serverScanMaxResults&quot;: 500,\n  &quot;drillThroughMaxResults&quot;: 300,\n  &quot;assignedTo&quot;: {\n    &quot;users&quot;: &#x5B;],\n    &quot;groups&quot;: &#x5B;&quot;Legal Team&quot;]\n  },\n  &quot;widgets&quot;: &#x5B;\n    {\n      &quot;id&quot;: &quot;&quot;,\n      &quot;title&quot;: &quot;Active Contracts&quot;,\n      &quot;type&quot;: &quot;kpiNumber&quot;,\n      &quot;gridColumnSpan&quot;: 3,\n      &quot;gridRowSpan&quot;: 2,\n      &quot;query&quot;: {\n        &quot;objectType&quot;: &quot;Document&quot;,\n        &quot;class&quot;: &quot;Contract or Agreement&quot;,\n        &quot;filters&quot;: &#x5B;\n          {\n            &quot;property&quot;: &quot;Effective through&quot;,\n            &quot;operator&quot;: &quot;greaterOrEqual&quot;,\n            &quot;value&quot;: &quot;@today&quot;,\n            &quot;valueType&quot;: &quot;dateToken&quot;\n          }\n        ],\n        &quot;aggregation&quot;: { &quot;type&quot;: &quot;summary&quot; }\n      },\n      &quot;display&quot;: { &quot;unit&quot;: &quot;contracts&quot; }\n    },\n    {\n      &quot;id&quot;: &quot;&quot;,\n      &quot;title&quot;: &quot;By Agreement Type&quot;,\n      &quot;type&quot;: &quot;donut&quot;,\n      &quot;gridColumnSpan&quot;: 9,\n      &quot;gridRowSpan&quot;: 2,\n      &quot;query&quot;: {\n        &quot;objectType&quot;: &quot;Document&quot;,\n        &quot;class&quot;: &quot;Contract or Agreement&quot;,\n        &quot;aggregation&quot;: {\n          &quot;type&quot;: &quot;groupByProperty&quot;,\n          &quot;propertyName&quot;: &quot;Agreement type&quot;,\n          &quot;resolveValueListLabels&quot;: &quot;Yes&quot;\n        }\n      }\n    }\n  ]\n}\n<\/pre><\/div>\n\n\n<p>This dashboard renders as a single KPI tile and a donut chart on the same row (3 + 9 = 12 columns), with auto-refresh every minute and access restricted to the Legal Team group. Nothing exotic, this is the kind of dashboard most customers should probably start with.<\/p>\n\n\n\n<p>If you wonder what it would look like, you can check the 1st and 2nd posts, they include these same widgets (though arranged slightly differently).<\/p>\n\n\n\n<h2 class=\"wp-block-heading\" id=\"h-8-what-comes-next\">8. What comes next<\/h2>\n\n\n\n<p>In the next three posts (4a, 4b, 4c) I will go through the seven widget types one family at a time:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>4a<\/strong> &#8211; Scalar widgets: <strong><em>kpiNumber<\/em><\/strong> and <strong><em>gauge<\/em><\/strong>.<\/li>\n\n\n\n<li><strong>4b<\/strong> &#8211; Trend widgets: <strong><em>line<\/em><\/strong> and <strong><em>area<\/em><\/strong>.<\/li>\n\n\n\n<li><strong>4c<\/strong> &#8211; Distribution and tabular widgets: <strong><em>donut<\/em><\/strong>, <strong><em>bar<\/em><\/strong>, <strong><em>table<\/em><\/strong>.<\/li>\n<\/ul>\n\n\n\n<p>After the widget tour, Post 5 covers the query side (object types, classes, filters, date tokens) and Post 6 covers aggregations and reducers. By the end of those, you will have everything needed to write a non-trivial dashboard from scratch &#8211; if that&#8217;s what you want to do&#8230; Or you can just use the Visual Designer and follow along.<\/p>\n\n\n\n<p>In the meantime, I hope this anatomy post gives you a clean mental map. If something is unclear or if you spotted a field whose behavior I have not explained here, please reach out so I can update the post.<\/p>\n\n\n\n<p>Want to know more about this Business Dashboard? <a href=\"https:\/\/www.dbi-services.com\/company\/contact\/\" target=\"_blank\" rel=\"noreferrer noopener\">Contact us<\/a> and we will be happy to showcase it on <a href=\"https:\/\/www.m-files.com\/\" target=\"_blank\" rel=\"noreferrer noopener\">M-Files<\/a>.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>In the previous post, I walked through what an end user sees when they open the Business Dashboard pane in M-Files. From this post on, the audience shifts more towards the administrator&#8217;s side, looking at how a dashboard is actually defined. Every dashboard is a single JSON document. The Admin tab in M-Files Admin offers [&hellip;]<\/p>\n","protected":false},"author":20,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[525],"tags":[4094,4102,694,3190,4099],"type_dbi":[],"class_list":["post-44952","post","type-post","status-publish","format-standard","hentry","category-enterprise-content-management","tag-business-dashboard","tag-dashboard","tag-json","tag-m-files","tag-widget"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v27.7 (Yoast SEO v27.7) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>M-Files BD - Anatomy of a dashboard definition - dbi Blog<\/title>\n<meta name=\"description\" content=\"Anatomy of an M-Files Business Dashboard JSON definition: dashboard-level fields, widget objects &amp; fields, the 12-column grid and storage.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"M-Files BD - Anatomy of a dashboard definition\" \/>\n<meta property=\"og:description\" content=\"Anatomy of an M-Files Business Dashboard JSON definition: dashboard-level fields, widget objects &amp; fields, the 12-column grid and storage.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/\" \/>\n<meta property=\"og:site_name\" content=\"dbi Blog\" \/>\n<meta property=\"article:published_time\" content=\"2026-06-07T14:52:03+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-06-07T14:52:05+00:00\" \/>\n<meta name=\"author\" content=\"Morgan Patou\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@MorganPatou\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Morgan Patou\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"10 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/\"},\"author\":{\"name\":\"Morgan Patou\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/c4d05b25843a9bc2ab20415dae6bd2d8\"},\"headline\":\"M-Files BD &#8211; Anatomy of a dashboard definition\",\"datePublished\":\"2026-06-07T14:52:03+00:00\",\"dateModified\":\"2026-06-07T14:52:05+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/\"},\"wordCount\":2114,\"commentCount\":0,\"keywords\":[\"Business Dashboard\",\"Dashboard\",\"json\",\"M-Files\",\"widget\"],\"articleSection\":[\"Enterprise content management\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/\",\"name\":\"M-Files BD - Anatomy of a dashboard definition - dbi Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-06-07T14:52:03+00:00\",\"dateModified\":\"2026-06-07T14:52:05+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/c4d05b25843a9bc2ab20415dae6bd2d8\"},\"description\":\"Anatomy of an M-Files Business Dashboard JSON definition: dashboard-level fields, widget objects & fields, the 12-column grid and storage.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/m-files-bd-anatomy-of-a-dashboard-definition\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"M-Files BD &#8211; Anatomy of a dashboard definition\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/\",\"name\":\"dbi Blog\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/#\\\/schema\\\/person\\\/c4d05b25843a9bc2ab20415dae6bd2d8\",\"name\":\"Morgan Patou\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5d7f5bec8b597db68a09107a6f5309e3870d6296ef94fb10ead4b09454ca67e5?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5d7f5bec8b597db68a09107a6f5309e3870d6296ef94fb10ead4b09454ca67e5?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/5d7f5bec8b597db68a09107a6f5309e3870d6296ef94fb10ead4b09454ca67e5?s=96&d=mm&r=g\",\"caption\":\"Morgan Patou\"},\"description\":\"Morgan Patou has over 15 years of experience in Digitalization &amp; Enterprise Content Management (ECM) systems, with a strong focus in recent years on platforms such as Alfresco, Documentum, and M-Files. He specializes in the architecture, setup, customization, and maintenance of ECM infrastructures in complex &amp; critical environments. Morgan is well-versed in both engineering and operations aspects, including high availability design, system integration, and lifecycle management. He also has a solid foundation in open-source and proprietary technologies - ranging from Apache HTTPD\\\/Tomcat, OpenLDAP or Kerberos to enterprise-grade systems like WebLogic. Morgan Patou holds an Engineering Degree in Computer Science from ENSISA (\u00c9cole Nationale Sup\u00e9rieure d'Ing\u00e9nieurs Sud Alsace) in Mulhouse, France. He is Alfresco Content Services Certified Administrator (ACSCA), Alfresco Content Services Certified Engineer (ACSCE) as well as OpenText Documentum Certified Administrator. His industry experience spans the Public Sector, IT Services, Financial Services\\\/Banking, and the Pharmaceutical industry.\",\"sameAs\":[\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/morgan-patou\\\/\",\"https:\\\/\\\/x.com\\\/MorganPatou\"],\"url\":\"https:\\\/\\\/www.dbi-services.com\\\/blog\\\/author\\\/morgan-patou\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"M-Files BD - Anatomy of a dashboard definition - dbi Blog","description":"Anatomy of an M-Files Business Dashboard JSON definition: dashboard-level fields, widget objects & fields, the 12-column grid and storage.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/","og_locale":"en_US","og_type":"article","og_title":"M-Files BD - Anatomy of a dashboard definition","og_description":"Anatomy of an M-Files Business Dashboard JSON definition: dashboard-level fields, widget objects & fields, the 12-column grid and storage.","og_url":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/","og_site_name":"dbi Blog","article_published_time":"2026-06-07T14:52:03+00:00","article_modified_time":"2026-06-07T14:52:05+00:00","author":"Morgan Patou","twitter_card":"summary_large_image","twitter_creator":"@MorganPatou","twitter_misc":{"Written by":"Morgan Patou","Est. reading time":"10 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/#article","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/"},"author":{"name":"Morgan Patou","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/c4d05b25843a9bc2ab20415dae6bd2d8"},"headline":"M-Files BD &#8211; Anatomy of a dashboard definition","datePublished":"2026-06-07T14:52:03+00:00","dateModified":"2026-06-07T14:52:05+00:00","mainEntityOfPage":{"@id":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/"},"wordCount":2114,"commentCount":0,"keywords":["Business Dashboard","Dashboard","json","M-Files","widget"],"articleSection":["Enterprise content management"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/","url":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/","name":"M-Files BD - Anatomy of a dashboard definition - dbi Blog","isPartOf":{"@id":"https:\/\/www.dbi-services.com\/blog\/#website"},"datePublished":"2026-06-07T14:52:03+00:00","dateModified":"2026-06-07T14:52:05+00:00","author":{"@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/c4d05b25843a9bc2ab20415dae6bd2d8"},"description":"Anatomy of an M-Files Business Dashboard JSON definition: dashboard-level fields, widget objects & fields, the 12-column grid and storage.","breadcrumb":{"@id":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.dbi-services.com\/blog\/m-files-bd-anatomy-of-a-dashboard-definition\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/www.dbi-services.com\/blog\/"},{"@type":"ListItem","position":2,"name":"M-Files BD &#8211; Anatomy of a dashboard definition"}]},{"@type":"WebSite","@id":"https:\/\/www.dbi-services.com\/blog\/#website","url":"https:\/\/www.dbi-services.com\/blog\/","name":"dbi Blog","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.dbi-services.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Person","@id":"https:\/\/www.dbi-services.com\/blog\/#\/schema\/person\/c4d05b25843a9bc2ab20415dae6bd2d8","name":"Morgan Patou","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/5d7f5bec8b597db68a09107a6f5309e3870d6296ef94fb10ead4b09454ca67e5?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/5d7f5bec8b597db68a09107a6f5309e3870d6296ef94fb10ead4b09454ca67e5?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/5d7f5bec8b597db68a09107a6f5309e3870d6296ef94fb10ead4b09454ca67e5?s=96&d=mm&r=g","caption":"Morgan Patou"},"description":"Morgan Patou has over 15 years of experience in Digitalization &amp; Enterprise Content Management (ECM) systems, with a strong focus in recent years on platforms such as Alfresco, Documentum, and M-Files. He specializes in the architecture, setup, customization, and maintenance of ECM infrastructures in complex &amp; critical environments. Morgan is well-versed in both engineering and operations aspects, including high availability design, system integration, and lifecycle management. He also has a solid foundation in open-source and proprietary technologies - ranging from Apache HTTPD\/Tomcat, OpenLDAP or Kerberos to enterprise-grade systems like WebLogic. Morgan Patou holds an Engineering Degree in Computer Science from ENSISA (\u00c9cole Nationale Sup\u00e9rieure d'Ing\u00e9nieurs Sud Alsace) in Mulhouse, France. He is Alfresco Content Services Certified Administrator (ACSCA), Alfresco Content Services Certified Engineer (ACSCE) as well as OpenText Documentum Certified Administrator. His industry experience spans the Public Sector, IT Services, Financial Services\/Banking, and the Pharmaceutical industry.","sameAs":["https:\/\/www.dbi-services.com\/blog\/author\/morgan-patou\/","https:\/\/x.com\/MorganPatou"],"url":"https:\/\/www.dbi-services.com\/blog\/author\/morgan-patou\/"}]}},"_links":{"self":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/44952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/comments?post=44952"}],"version-history":[{"count":8,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/44952\/revisions"}],"predecessor-version":[{"id":44960,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/posts\/44952\/revisions\/44960"}],"wp:attachment":[{"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/media?parent=44952"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/categories?post=44952"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/tags?post=44952"},{"taxonomy":"type","embeddable":true,"href":"https:\/\/www.dbi-services.com\/blog\/wp-json\/wp\/v2\/type_dbi?post=44952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}