@datarails-ai/dr-appspace-cli 0.9.6 → 0.9.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +2 -2
  2. package/dist/cli.js +316 -37
  3. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -13,7 +13,7 @@ import { fileURLToPath as fileURLToPath6 } from "url";
13
13
  // package.json
14
14
  var package_default = {
15
15
  name: "@datarails-ai/dr-appspace-cli",
16
- version: "0.9.6",
16
+ version: "0.9.7",
17
17
  description: "Datarails App Space CLI \u2014 build, try, push and publish App Space apps",
18
18
  type: "module",
19
19
  engines: {
@@ -57,7 +57,7 @@ var package_default = {
57
57
  };
58
58
 
59
59
  // src/buildInfo.ts
60
- var BUILD_TIME = "2026-09-30T11:51:42.653Z";
60
+ var BUILD_TIME = "2026-09-30T12:27:06.209Z";
61
61
  function formatBuildTime(iso) {
62
62
  if (iso === "") return "";
63
63
  const d = new Date(iso);
@@ -3964,11 +3964,16 @@ __export(components_gen_exports, {
3964
3964
  CONTROL_PARTS: () => CONTROL_PARTS,
3965
3965
  DASHBOARD_TYPES: () => DASHBOARD_TYPES,
3966
3966
  ELEMENT_TYPES: () => ELEMENT_TYPES,
3967
+ FORMAT_PATTERNS: () => FORMAT_PATTERNS,
3967
3968
  HANDLER_ROLES: () => HANDLER_ROLES,
3968
3969
  KIND_READS: () => KIND_READS,
3969
3970
  LIBRARY_PROPS_SCHEMAS: () => LIBRARY_PROPS_SCHEMAS,
3970
3971
  LIBRARY_TYPES: () => LIBRARY_TYPES,
3972
+ MODULE_OF: () => MODULE_OF,
3973
+ NEGATIVE_MODES: () => NEGATIVE_MODES,
3971
3974
  PARTS: () => PARTS,
3975
+ PLATFORM_FORMAT: () => PLATFORM_FORMAT,
3976
+ PLATFORM_NUMBERS: () => PLATFORM_NUMBERS,
3972
3977
  PROPS_SCHEMAS: () => PROPS_SCHEMAS,
3973
3978
  REGISTRY_VERSION: () => REGISTRY_VERSION,
3974
3979
  STAT_TONES: () => STAT_TONES,
@@ -3976,23 +3981,28 @@ __export(components_gen_exports, {
3976
3981
  TITLED_TYPES: () => TITLED_TYPES,
3977
3982
  WIDGET_KINDS: () => WIDGET_KINDS
3978
3983
  });
3979
- var REGISTRY_VERSION = Object.freeze(6);
3984
+ var REGISTRY_VERSION = Object.freeze(7);
3980
3985
  var ELEMENT_TYPES = Object.freeze(["region", "grid", "widget", "control", "nav", "tab", "slot", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "field", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
3981
3986
  var COMPONENT_TYPES = Object.freeze(["widget", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
3982
3987
  var APP_TYPES = Object.freeze(["widget", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "field", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
3983
3988
  var DASHBOARD_TYPES = Object.freeze(["region", "grid", "control", "nav", "tab", "slot"]);
3984
- var COMPONENT_ATTRIBUTES = Object.freeze(["data-dr-component", "data-dr-entity", "data-dr-action", "data-dr-source", "data-dr-field", "data-dr-param", "data-dr-role", "data-dr-filter", "data-dr-id", "data-dr-label", "data-dr-measure", "data-dr-tone", "data-dr-kind", "data-dr-x", "data-dr-y", "data-dr-series", "data-dr-format", "data-dr-module", "data-dr-args", "data-dr-props", "data-dr-declares"]);
3985
- var COMPONENT_PROPS = Object.freeze([["data-dr-entity", "entity"], ["data-dr-action", "action"], ["data-dr-source", "source"], ["data-dr-field", "field"], ["data-dr-param", "param"], ["data-dr-role", "role"], ["data-dr-id", "id"], ["data-dr-label", "label"], ["data-dr-measure", "measure"], ["data-dr-tone", "tone"], ["data-dr-kind", "kind"], ["data-dr-x", "x"], ["data-dr-y", "y"], ["data-dr-series", "series"], ["data-dr-format", "format"], ["data-dr-module", "module"]]);
3989
+ var COMPONENT_ATTRIBUTES = Object.freeze(["data-dr-component", "data-dr-entity", "data-dr-action", "data-dr-source", "data-dr-field", "data-dr-param", "data-dr-role", "data-dr-filter", "data-dr-id", "data-dr-label", "data-dr-measure", "data-dr-tone", "data-dr-kind", "data-dr-x", "data-dr-y", "data-dr-series", "data-dr-format", "data-dr-negative", "data-dr-module", "data-dr-args", "data-dr-props", "data-dr-declares"]);
3990
+ var COMPONENT_PROPS = Object.freeze([["data-dr-entity", "entity"], ["data-dr-action", "action"], ["data-dr-source", "source"], ["data-dr-field", "field"], ["data-dr-param", "param"], ["data-dr-role", "role"], ["data-dr-id", "id"], ["data-dr-label", "label"], ["data-dr-measure", "measure"], ["data-dr-tone", "tone"], ["data-dr-kind", "kind"], ["data-dr-x", "x"], ["data-dr-y", "y"], ["data-dr-series", "series"], ["data-dr-format", "format"], ["data-dr-negative", "negative"], ["data-dr-module", "module"]]);
3986
3991
  var HANDLER_ROLES = Object.freeze(["list", "save", "remove", "submit", "inbox", "decide", "summary", "history", "custom"]);
3987
3992
  var CHART_KINDS = Object.freeze(["line", "bar", "area"]);
3988
3993
  var CHART_FORMATS = Object.freeze(["currency", "number", "percent"]);
3994
+ var PLATFORM_FORMAT = Object.freeze({ "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$" });
3995
+ var NEGATIVE_MODES = Object.freeze(["minus", "red_minus", "absolute", "red_absolute"]);
3996
+ var FORMAT_PATTERNS = Object.freeze({ "currency": "$#,###", "number": "#,###", "percent": '#,###.#"%"' });
3997
+ var PLATFORM_NUMBERS = Object.freeze({ "dr-app-runtime": "1.8.0", "dr-app-widgets": "1.2.0", "dr-components": "1.2.0", "dr-components-controls": "1.1.0" });
3998
+ var MODULE_OF = Object.freeze({ "widget": "dr-app-widgets", "form": "dr-app-runtime", "list": "dr-app-runtime", "detail": "dr-app-runtime", "queue": "dr-app-runtime", "action": "dr-app-runtime", "filter": "dr-app-runtime", "stat": "dr-app-runtime", "chart": "dr-app-runtime", "custom": "dr-app-runtime", "field": "dr-app-runtime", "number_input": "dr-components", "tabs": "dr-components", "tab_panel": "dr-components", "select": "dr-components", "date_picker": "dr-components", "data_grid": "dr-components", "dialog": "dr-components", "variance_table": "dr-components", "toggle": "dr-components", "control_group": "dr-components", "callout": "dr-components", "scenario_columns": "dr-components", "slider": "dr-components-controls" });
3989
3999
  var STAT_TONES = Object.freeze(["default", "positive", "warning", "negative"]);
3990
4000
  var WIDGET_KINDS = Object.freeze(["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"]);
3991
4001
  var KIND_READS = Object.freeze({ "line": ["series"], "area": ["series"], "bar": ["series", "breakdown"], "stacked": ["series"], "pie": ["breakdown"], "donut": ["breakdown"], "kpi": ["kpi"], "candle": ["ohlc"], "bubble": ["scatter"], "table": ["table"], "narrative": ["narrative"] });
3992
4002
  var STRICT_TYPES = Object.freeze(["number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
3993
- var PROPS_SCHEMAS = Object.freeze({ "region": { "type": "object", "properties": {} }, "grid": { "type": "object", "properties": {} }, "widget": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the card's title on an app page" }, "role": { "type": "string", "description": "data-dr-role: the app role this card is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "kind": { "enum": ["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"], "description": "data-dr-kind on an app page, the widget kind on a dashboard" }, "source": { "type": "string", "description": "the handler whose payload an app card draws (data-dr-source), or the SPEC key a dashboard card draws" }, "format": { "enum": ["currency", "number", "percent"], "description": "data-dr-format: how the card's numbers read" }, "title": { "type": "string", "description": "a dashboard card's title" }, "subtitle": { "type": "string", "description": "the line under a dashboard card's title" }, "description": { "type": "string", "description": "what a dashboard card shows, in words" }, "params": { "type": "array", "description": "the params a dashboard card honours" } } }, "control": { "type": "object", "properties": { "param": { "type": "string", "description": "the param it moves" }, "control_kind": { "type": "string", "description": "the control's kind" }, "type": { "type": "string", "description": "the input type" }, "min": { "type": "string", "description": "the lowest value" }, "max": { "type": "string", "description": "the highest value" }, "step": { "type": "string", "description": "the step" }, "value": { "type": "string", "description": "the starting value" }, "label": { "type": "string", "description": "the label" } } }, "nav": { "type": "object", "properties": { "aria_label": { "type": "string", "description": "the nav's accessible name" } } }, "tab": { "type": "object", "properties": { "current": { "type": "boolean", "description": "true on the page it names" }, "href": { "type": "string", "description": "the page it links to" }, "label": { "type": "string", "description": "the text it shows" } } }, "slot": { "type": "object", "properties": {} }, "form": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the form writes" }, "action": { "type": "string", "description": "data-dr-action: the handler that saves it" } } }, "list": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table listed" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers the rows" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "detail": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the row is from" }, "action": { "type": "string", "description": "data-dr-action: the handler it acts through" } } }, "queue": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table queued" }, "source": { "type": "string", "description": "data-dr-source: the inbox handler" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "action": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "action": { "type": "string", "description": "data-dr-action: the handler it runs" }, "param": { "type": "string", "description": "data-dr-param: the argument it passes" }, "entity": { "type": "string", "description": "data-dr-entity: the table the handler acts on" } } }, "filter": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "field": { "type": "string", "description": "data-dr-field: the column filtered" }, "entity": { "type": "string", "description": "data-dr-entity: the table filtered" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "stat": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the summary handler" }, "measure": { "type": "string", "description": "data-dr-measure: the key of the number shown" }, "tone": { "type": "string", "description": "data-dr-tone: default | positive | warning | negative" } } }, "chart": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows it draws" }, "kind": { "enum": ["line", "bar", "area"], "description": "data-dr-kind: what it draws" }, "x": { "type": "string", "description": "data-dr-x: the column on the category axis" }, "y": { "type": "string", "description": "data-dr-y: the one numeric column drawn" }, "series": { "type": "string", "description": "data-dr-series: the column whose distinct values are one line each" }, "format": { "enum": ["currency", "number", "percent"], "description": "data-dr-format: how a number reads; percent is a value already in percent units" } } }, "custom": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose answer the module receives" }, "module": { "type": "string", "pattern": "^components/[a-z][a-z0-9_-]*\\.js$", "description": "data-dr-module: the file that draws it" }, "args": { "type": "object", "description": "data-dr-args: one JSON object handed to the module as ui.args; absent means {}" }, "declares": { "type": "object", "description": "data-dr-declares: what the module does, stated for graders and app-space test \u2014 nothing draws from it and the runtime never reads it. Every key is optional; a name it lists must be one the contract declares (custom_declares)", "additionalProperties": false, "properties": { "reads": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the data.sources entries and handlers whose answers it draws" }, "calls": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the handlers it calls through ui.call; app-space test reports a call to any other (custom-undeclared-call)" }, "produces": { "type": "object", "description": `per called handler, the payload keys it sends \u2014 {"project": ["growth", "hires"]}; for a handler it does not list, app-space test reads the keys off the module's ui.call object literal`, "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "shows": { "type": "array", "description": "the numbers it displays; the module projects each one on the element that shows it (data-dr-field, data-dr-value, data-dr-format), which app-space test harvests into the element's values", "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the field the number is, as its data-dr-field names it" }, "format": { "enum": ["currency", "number", "percent"], "description": "how it reads, as its data-dr-format says" }, "scale": { "enum": ["fraction"], "description": "fraction: the value is a share (0.04) shown as a percent (4%)" } } } } } } } }, "field": { "type": "object", "properties": { "entity": { "type": "string", "description": "data-dr-entity: the table the column is in" }, "field": { "type": "string", "description": "data-dr-field: the column" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers its choices" }, "label": { "type": "string", "description": "the field's label" }, "required": { "type": "boolean", "description": "true when the form cannot be saved without it" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "enum": ["currency", "number", "percent"], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent", "text", "date"], "description": "how the value reads; default text" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "enum": ["currency", "number", "percent"], "description": "how actual, plan and variance read; default currency" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent"], "description": "how the value reads" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } }, "slider": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this slider writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this slider reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "min": { "type": "number", "description": "the track's low end, in stored units; default the page param's min (param mode), else 0" }, "max": { "type": "number", "description": "the track's high end, in stored units; default the page param's max (param mode). Required one way or the other: a slider with neither draws its 'slider needs a max' panel (1.0.1) and the compiler refuses it (part_bounds)" }, "step": { "type": "number", "description": "the increment the value moves by, in stored units; every value set is a multiple of it from min; default the page param's step, else 1" }, "format": { "enum": ["currency", "number", "percent"], "description": "how the value beside the track reads; default number" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "show_value": { "type": "boolean", "description": "whether the formatted value is drawn beside the track; default true" }, "marks": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value"], "properties": { "value": { "type": "number", "description": "where the mark sits, in stored units" }, "label": { "type": "string", "description": "what the mark says; default the value, formatted" } } }, "description": "labelled ticks under the track" }, "value": { "type": "number", "description": "field mode: the value it starts on; default min. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the slider's label; default the page param's label (param mode), else the element's label" } }, "description": "data-dr-props: the slider part's typed props, handed to it as PartProps.props" } } } });
4003
+ var PROPS_SCHEMAS = Object.freeze({ "region": { "type": "object", "properties": {} }, "grid": { "type": "object", "properties": {} }, "widget": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the card's title on an app page" }, "role": { "type": "string", "description": "data-dr-role: the app role this card is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "kind": { "enum": ["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"], "description": "data-dr-kind on an app page, the widget kind on a dashboard" }, "source": { "type": "string", "description": "the handler whose payload an app card draws (data-dr-source), or the SPEC key a dashboard card draws" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "data-dr-format: how the card's numbers read" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "title": { "type": "string", "description": "a dashboard card's title" }, "subtitle": { "type": "string", "description": "the line under a dashboard card's title" }, "description": { "type": "string", "description": "what a dashboard card shows, in words" }, "params": { "type": "array", "description": "the params a dashboard card honours" } } }, "control": { "type": "object", "properties": { "param": { "type": "string", "description": "the param it moves" }, "control_kind": { "type": "string", "description": "the control's kind" }, "type": { "type": "string", "description": "the input type" }, "min": { "type": "string", "description": "the lowest value" }, "max": { "type": "string", "description": "the highest value" }, "step": { "type": "string", "description": "the step" }, "value": { "type": "string", "description": "the starting value" }, "label": { "type": "string", "description": "the label" } } }, "nav": { "type": "object", "properties": { "aria_label": { "type": "string", "description": "the nav's accessible name" } } }, "tab": { "type": "object", "properties": { "current": { "type": "boolean", "description": "true on the page it names" }, "href": { "type": "string", "description": "the page it links to" }, "label": { "type": "string", "description": "the text it shows" } } }, "slot": { "type": "object", "properties": {} }, "form": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the form writes" }, "action": { "type": "string", "description": "data-dr-action: the handler that saves it" } } }, "list": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table listed" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers the rows" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "detail": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the row is from" }, "action": { "type": "string", "description": "data-dr-action: the handler it acts through" } } }, "queue": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table queued" }, "source": { "type": "string", "description": "data-dr-source: the inbox handler" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "action": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "action": { "type": "string", "description": "data-dr-action: the handler it runs" }, "param": { "type": "string", "description": "data-dr-param: the argument it passes" }, "entity": { "type": "string", "description": "data-dr-entity: the table the handler acts on" } } }, "filter": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "field": { "type": "string", "description": "data-dr-field: the column filtered" }, "entity": { "type": "string", "description": "data-dr-entity: the table filtered" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "stat": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the summary handler" }, "measure": { "type": "string", "description": "data-dr-measure: the key of the number shown" }, "tone": { "type": "string", "description": "data-dr-tone: default | positive | warning | negative" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "data-dr-format: how the figure reads: a word or a platform format string" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" } } }, "chart": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows it draws" }, "kind": { "enum": ["line", "bar", "area"], "description": "data-dr-kind: what it draws" }, "x": { "type": "string", "description": "data-dr-x: the column on the category axis" }, "y": { "type": "string", "description": "data-dr-y: the one numeric column drawn" }, "series": { "type": "string", "description": "data-dr-series: the column whose distinct values are one line each" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "data-dr-format: how a number reads; percent is a value already in percent units" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" } } }, "custom": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose answer the module receives" }, "module": { "type": "string", "pattern": "^components/[a-z][a-z0-9_-]*\\.js$", "description": "data-dr-module: the file that draws it" }, "args": { "type": "object", "description": "data-dr-args: one JSON object handed to the module as ui.args; absent means {}" }, "declares": { "type": "object", "description": "data-dr-declares: what the module does, stated for graders and app-space test \u2014 nothing draws from it and the runtime never reads it. Every key is optional; a name it lists must be one the contract declares (custom_declares)", "additionalProperties": false, "properties": { "reads": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the data.sources entries and handlers whose answers it draws" }, "calls": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the handlers it calls through ui.call; app-space test reports a call to any other (custom-undeclared-call)" }, "produces": { "type": "object", "description": `per called handler, the payload keys it sends \u2014 {"project": ["growth", "hires"]}; for a handler it does not list, app-space test reads the keys off the module's ui.call object literal`, "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "shows": { "type": "array", "description": "the numbers it displays; the module projects each one on the element that shows it (data-dr-field, data-dr-value, data-dr-format), which app-space test harvests into the element's values", "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the field the number is, as its data-dr-field names it" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how it reads, as its data-dr-format says" }, "scale": { "enum": ["fraction"], "description": "fraction: the value is a share (0.04) shown as a percent (4%)" } } } } } } } }, "field": { "type": "object", "properties": { "entity": { "type": "string", "description": "data-dr-entity: the table the column is in" }, "field": { "type": "string", "description": "data-dr-field: the column" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers its choices" }, "label": { "type": "string", "description": "the field's label" }, "required": { "type": "boolean", "description": "true when the form cannot be saved without it" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent", "text", "date"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads; default text" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how actual, plan and variance read; default currency" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how actual, plan and variance read below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } }, "slider": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this slider writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this slider reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "min": { "type": "number", "description": "the track's low end, in stored units; default the page param's min (param mode), else 0" }, "max": { "type": "number", "description": "the track's high end, in stored units; default the page param's max (param mode). Required one way or the other: a slider with neither draws its 'slider needs a max' panel (1.0.1) and the compiler refuses it (part_bounds)" }, "step": { "type": "number", "description": "the increment the value moves by, in stored units; every value set is a multiple of it from min; default the page param's step, else 1" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value beside the track reads; default number" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "show_value": { "type": "boolean", "description": "whether the formatted value is drawn beside the track; default true" }, "marks": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value"], "properties": { "value": { "type": "number", "description": "where the mark sits, in stored units" }, "label": { "type": "string", "description": "what the mark says; default the value, formatted" } } }, "description": "labelled ticks under the track" }, "value": { "type": "number", "description": "field mode: the value it starts on; default min. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the slider's label; default the page param's label (param mode), else the element's label" } }, "description": "data-dr-props: the slider part's typed props, handed to it as PartProps.props" } } } });
3994
4004
  var LIBRARY_TYPES = Object.freeze(["number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns"]);
3995
- var LIBRARY_PROPS_SCHEMAS = Object.freeze({ "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "enum": ["currency", "number", "percent"], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent", "text", "date"], "description": "how the value reads; default text" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "enum": ["currency", "number", "percent"], "description": "how actual, plan and variance read; default currency" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent"], "description": "how the value reads" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } } });
4005
+ var LIBRARY_PROPS_SCHEMAS = Object.freeze({ "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent", "text", "date"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads; default text" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how actual, plan and variance read; default currency" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how actual, plan and variance read below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } } });
3996
4006
  var CONTROLS_TYPES = Object.freeze(["slider"]);
3997
4007
  var PARTS = Object.freeze({ "number_input": { "module": "dr-components", "reads": null, "children": "none", "events": {}, "empty": null }, "tabs": { "module": "dr-components", "reads": null, "children": ["tab_panel"], "events": {}, "empty": null }, "tab_panel": { "module": "dr-components", "reads": null, "children": "any", "events": {}, "empty": null }, "select": { "module": "dr-components", "reads": { "roles": ["list", "custom"], "as": "rows" }, "children": "none", "events": {}, "empty": null }, "date_picker": { "module": "dr-components", "reads": null, "children": "none", "events": {}, "empty": null }, "data_grid": { "module": "dr-components", "reads": { "roles": ["list", "inbox", "custom"], "as": "rows" }, "children": "none", "events": { "on_row": ["custom", "decide"], "on_row_action": ["remove", "decide", "custom", "submit", "save"] }, "empty": "Nothing to show." }, "dialog": { "module": "dr-components", "reads": null, "children": "any", "events": { "on_confirm": ["custom", "save", "submit", "decide"] }, "empty": null }, "variance_table": { "module": "dr-components", "reads": { "roles": ["list", "custom"], "as": "rows" }, "children": "none", "events": {}, "empty": "Nothing to show." }, "toggle": { "module": "dr-components", "reads": null, "children": "none", "events": {}, "empty": null }, "control_group": { "module": "dr-components", "reads": null, "children": ["number_input", "select", "date_picker", "toggle", "slider"], "events": {}, "empty": null }, "callout": { "module": "dr-components", "reads": { "roles": ["summary", "list", "custom"], "as": "payload" }, "children": "none", "events": {}, "empty": null }, "scenario_columns": { "module": "dr-components", "reads": { "roles": ["list", "custom"], "as": "rows" }, "children": "none", "events": {}, "empty": "Nothing to show." }, "slider": { "module": "dr-components-controls", "reads": null, "children": "none", "events": {}, "empty": null } });
3998
4008
  var TITLED_TYPES = Object.freeze(["widget", "form", "list", "queue", "stat", "chart", "custom", "number_input", "select", "date_picker", "dialog"]);
@@ -4017,6 +4027,27 @@ var CHART_KINDS2 = CHART_KINDS;
4017
4027
  var WIDGET_KINDS2 = WIDGET_KINDS;
4018
4028
  var KIND_READS2 = KIND_READS;
4019
4029
  var CHART_FORMATS2 = CHART_FORMATS;
4030
+ var NEGATIVE_MODES2 = NEGATIVE_MODES;
4031
+ var FORMAT_PATTERNS2 = FORMAT_PATTERNS;
4032
+ var PLATFORM_FORMAT_RE = new RegExp(PLATFORM_FORMAT.pattern, "u");
4033
+ function isPlatformFormat(value) {
4034
+ return typeof value === "string" && value.length <= PLATFORM_FORMAT.maxLength && PLATFORM_FORMAT_RE.test(value);
4035
+ }
4036
+ var PLATFORM_NUMBERS2 = PLATFORM_NUMBERS;
4037
+ var MODULE_OF2 = MODULE_OF;
4038
+ var semver = (version) => String(version ?? "").split(".").map((part) => Number.parseInt(part, 10) || 0);
4039
+ function drawsPlatformNumbers(pin) {
4040
+ const at = String(pin ?? "").lastIndexOf("@");
4041
+ const module = at > 0 ? pin.slice(0, at) : String(pin ?? "");
4042
+ const first = PLATFORM_NUMBERS2[module];
4043
+ if (typeof first !== "string") return false;
4044
+ const [a, b] = [semver(pin.slice(at + 1)), semver(first)];
4045
+ for (let i = 0; i < 3; i++) if ((a[i] ?? 0) !== (b[i] ?? 0)) return (a[i] ?? 0) > (b[i] ?? 0);
4046
+ return true;
4047
+ }
4048
+ function isNumberFormat(value, words = CHART_FORMATS2) {
4049
+ return typeof value === "string" && words.includes(value) || isPlatformFormat(value);
4050
+ }
4020
4051
  var COMPONENT_PROPS2 = COMPONENT_PROPS;
4021
4052
  function parseFilter(raw) {
4022
4053
  const filter = {};
@@ -7697,6 +7728,8 @@ var COMPONENT_PROPS3 = /* @__PURE__ */ new Set([
7697
7728
  "y",
7698
7729
  "series",
7699
7730
  "format",
7731
+ // The platform's negative-number mode on a stat, a chart or a widget (`data-dr-negative`, P1b).
7732
+ "negative",
7700
7733
  // A custom component's: the file under ui/ that draws it, and its one JSON prop.
7701
7734
  "module",
7702
7735
  "args",
@@ -7722,6 +7755,7 @@ var WIDGET_PROPS = /* @__PURE__ */ new Set([
7722
7755
  ]);
7723
7756
  var CHART_KINDS3 = CHART_KINDS2;
7724
7757
  var CHART_FORMATS3 = CHART_FORMATS2;
7758
+ var isNumberFormat2 = isNumberFormat;
7725
7759
  var STAT_TONES2 = registry.STAT_TONES;
7726
7760
  var HANDLER_ROLES2 = registry.HANDLER_ROLES;
7727
7761
  var INJECTED_COLUMNS2 = [
@@ -7839,7 +7873,7 @@ var contract_schema_default = {
7839
7873
  properties: {
7840
7874
  file: { type: "string" },
7841
7875
  tokens: { type: "object", additionalProperties: { type: "string" } },
7842
- preset: { type: "string", enum: ["default", "slate", "warm", "contrast", "presentation"], description: "OPTIONAL. A named look from ui-kit/v4; absent means default. The compiler fills pages[].theme/density where a page states none from this and app.theme.density, and drops both keys from the filled contract it compares (mirrors fillHeaders)." },
7876
+ preset: { type: "string", enum: ["default", "slate", "warm", "contrast", "presentation"], description: "OPTIONAL. A named look from the pinned ui-kit (presentation is refused: ui-kit/v4 shipped without it); absent means default. The compiler fills pages[].theme/density where a page states none from this and app.theme.density, and drops both keys from the filled contract it compares (mirrors fillHeaders)." },
7843
7877
  density: { type: "string", enum: ["comfortable", "compact"], description: "OPTIONAL. app.theme.density; absent means comfortable. Distinct from pages[].density, which is the compiled data-dr-density string." }
7844
7878
  }
7845
7879
  }
@@ -8464,7 +8498,7 @@ var contract_schema_default = {
8464
8498
  },
8465
8499
  props_region: { type: "object", properties: {} },
8466
8500
  props_grid: { type: "object", properties: {} },
8467
- props_widget: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the card's title on an app page" }, role: { type: "string", description: "data-dr-role: the app role this card is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, kind: { enum: ["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"], description: "data-dr-kind on an app page, the widget kind on a dashboard" }, source: { type: "string", description: "the handler whose payload an app card draws (data-dr-source), or the SPEC key a dashboard card draws" }, format: { enum: ["currency", "number", "percent"], description: "data-dr-format: how the card's numbers read" }, title: { type: "string", description: "a dashboard card's title" }, subtitle: { type: "string", description: "the line under a dashboard card's title" }, description: { type: "string", description: "what a dashboard card shows, in words" }, params: { type: "array", description: "the params a dashboard card honours" } } },
8501
+ props_widget: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the card's title on an app page" }, role: { type: "string", description: "data-dr-role: the app role this card is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, kind: { enum: ["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"], description: "data-dr-kind on an app page, the widget kind on a dashboard" }, source: { type: "string", description: "the handler whose payload an app card draws (data-dr-source), or the SPEC key a dashboard card draws" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "data-dr-format: how the card's numbers read" }, negative: { enum: ["minus", "red_minus", "absolute", "red_absolute"], description: "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, title: { type: "string", description: "a dashboard card's title" }, subtitle: { type: "string", description: "the line under a dashboard card's title" }, description: { type: "string", description: "what a dashboard card shows, in words" }, params: { type: "array", description: "the params a dashboard card honours" } } },
8468
8502
  props_control: { type: "object", properties: { param: { type: "string", description: "the param it moves" }, control_kind: { type: "string", description: "the control's kind" }, type: { type: "string", description: "the input type" }, min: { type: "string", description: "the lowest value" }, max: { type: "string", description: "the highest value" }, step: { type: "string", description: "the step" }, value: { type: "string", description: "the starting value" }, label: { type: "string", description: "the label" } } },
8469
8503
  props_nav: { type: "object", properties: { aria_label: { type: "string", description: "the nav's accessible name" } } },
8470
8504
  props_tab: { type: "object", properties: { current: { type: "boolean", description: "true on the page it names" }, href: { type: "string", description: "the page it links to" }, label: { type: "string", description: "the text it shows" } } },
@@ -8475,23 +8509,23 @@ var contract_schema_default = {
8475
8509
  props_queue: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, entity: { type: "string", description: "data-dr-entity: the table queued" }, source: { type: "string", description: "data-dr-source: the inbox handler" }, filter: { description: "data-dr-filter, parsed from `col=value` into an object" } } },
8476
8510
  props_action: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, action: { type: "string", description: "data-dr-action: the handler it runs" }, param: { type: "string", description: "data-dr-param: the argument it passes" }, entity: { type: "string", description: "data-dr-entity: the table the handler acts on" } } },
8477
8511
  props_filter: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, field: { type: "string", description: "data-dr-field: the column filtered" }, entity: { type: "string", description: "data-dr-entity: the table filtered" }, input_type: { type: "string", description: "the input's type" }, options: { type: "array", description: "the choices offered" } } },
8478
- props_stat: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the summary handler" }, measure: { type: "string", description: "data-dr-measure: the key of the number shown" }, tone: { type: "string", description: "data-dr-tone: default | positive | warning | negative" } } },
8479
- props_chart: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose rows it draws" }, kind: { enum: ["line", "bar", "area"], description: "data-dr-kind: what it draws" }, x: { type: "string", description: "data-dr-x: the column on the category axis" }, y: { type: "string", description: "data-dr-y: the one numeric column drawn" }, series: { type: "string", description: "data-dr-series: the column whose distinct values are one line each" }, format: { enum: ["currency", "number", "percent"], description: "data-dr-format: how a number reads; percent is a value already in percent units" } } },
8480
- props_custom: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose answer the module receives" }, module: { type: "string", pattern: "^components/[a-z][a-z0-9_-]*\\.js$", description: "data-dr-module: the file that draws it" }, args: { type: "object", description: "data-dr-args: one JSON object handed to the module as ui.args; absent means {}" }, declares: { type: "object", description: "data-dr-declares: what the module does, stated for graders and app-space test \u2014 nothing draws from it and the runtime never reads it. Every key is optional; a name it lists must be one the contract declares (custom_declares)", additionalProperties: false, properties: { reads: { type: "array", items: { type: "string", minLength: 1 }, description: "the data.sources entries and handlers whose answers it draws" }, calls: { type: "array", items: { type: "string", minLength: 1 }, description: "the handlers it calls through ui.call; app-space test reports a call to any other (custom-undeclared-call)" }, produces: { type: "object", description: `per called handler, the payload keys it sends \u2014 {"project": ["growth", "hires"]}; for a handler it does not list, app-space test reads the keys off the module's ui.call object literal`, additionalProperties: { type: "array", items: { type: "string", minLength: 1 } } }, shows: { type: "array", description: "the numbers it displays; the module projects each one on the element that shows it (data-dr-field, data-dr-value, data-dr-format), which app-space test harvests into the element's values", items: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the field the number is, as its data-dr-field names it" }, format: { enum: ["currency", "number", "percent"], description: "how it reads, as its data-dr-format says" }, scale: { enum: ["fraction"], description: "fraction: the value is a share (0.04) shown as a percent (4%)" } } } } } } } },
8512
+ props_stat: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the summary handler" }, measure: { type: "string", description: "data-dr-measure: the key of the number shown" }, tone: { type: "string", description: "data-dr-tone: default | positive | warning | negative" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "data-dr-format: how the figure reads: a word or a platform format string" }, negative: { enum: ["minus", "red_minus", "absolute", "red_absolute"], description: "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" } } },
8513
+ props_chart: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose rows it draws" }, kind: { enum: ["line", "bar", "area"], description: "data-dr-kind: what it draws" }, x: { type: "string", description: "data-dr-x: the column on the category axis" }, y: { type: "string", description: "data-dr-y: the one numeric column drawn" }, series: { type: "string", description: "data-dr-series: the column whose distinct values are one line each" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "data-dr-format: how a number reads; percent is a value already in percent units" }, negative: { enum: ["minus", "red_minus", "absolute", "red_absolute"], description: "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" } } },
8514
+ props_custom: { type: "object", properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose answer the module receives" }, module: { type: "string", pattern: "^components/[a-z][a-z0-9_-]*\\.js$", description: "data-dr-module: the file that draws it" }, args: { type: "object", description: "data-dr-args: one JSON object handed to the module as ui.args; absent means {}" }, declares: { type: "object", description: "data-dr-declares: what the module does, stated for graders and app-space test \u2014 nothing draws from it and the runtime never reads it. Every key is optional; a name it lists must be one the contract declares (custom_declares)", additionalProperties: false, properties: { reads: { type: "array", items: { type: "string", minLength: 1 }, description: "the data.sources entries and handlers whose answers it draws" }, calls: { type: "array", items: { type: "string", minLength: 1 }, description: "the handlers it calls through ui.call; app-space test reports a call to any other (custom-undeclared-call)" }, produces: { type: "object", description: `per called handler, the payload keys it sends \u2014 {"project": ["growth", "hires"]}; for a handler it does not list, app-space test reads the keys off the module's ui.call object literal`, additionalProperties: { type: "array", items: { type: "string", minLength: 1 } } }, shows: { type: "array", description: "the numbers it displays; the module projects each one on the element that shows it (data-dr-field, data-dr-value, data-dr-format), which app-space test harvests into the element's values", items: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the field the number is, as its data-dr-field names it" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "how it reads, as its data-dr-format says" }, scale: { enum: ["fraction"], description: "fraction: the value is a share (0.04) shown as a percent (4%)" } } } } } } } },
8481
8515
  props_field: { type: "object", properties: { entity: { type: "string", description: "data-dr-entity: the table the column is in" }, field: { type: "string", description: "data-dr-field: the column" }, source: { type: "string", description: "data-dr-source: the handler that answers its choices" }, label: { type: "string", description: "the field's label" }, required: { type: "boolean", description: "true when the form cannot be saved without it" }, input_type: { type: "string", description: "the input's type" }, options: { type: "array", description: "the choices offered" } } },
8482
- props_number_input: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, required: ["format"], properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, format: { enum: ["currency", "number", "percent"], description: "what the number is: the unit shown beside the input" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, min: { type: "number", description: "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, max: { type: "number", description: "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, step: { type: "number", description: "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, decimals: { type: "integer", minimum: 0, description: "the decimals the STORED value is rounded to, after scaling; default as typed" }, value: { type: "number", description: "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, label: { type: "string", description: "the input's label; default the page param's label (param mode), else the element's label" }, placeholder: { type: "string", description: "the hint shown while the input is empty" } }, description: "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } },
8516
+ props_number_input: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, required: ["format"], properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "what the number is: the unit shown beside the input" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, min: { type: "number", description: "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, max: { type: "number", description: "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, step: { type: "number", description: "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, decimals: { type: "integer", minimum: 0, description: "the decimals the STORED value is rounded to, after scaling; default as typed" }, value: { type: "number", description: "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, label: { type: "string", description: "the input's label; default the page param's label (param mode), else the element's label" }, placeholder: { type: "string", description: "the hint shown while the input is empty" } }, description: "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } },
8483
8517
  props_tabs: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, required: ["tabs"], properties: { tabs: { type: "array", minItems: 1, items: { type: "object", additionalProperties: false, required: ["id", "label"], properties: { id: { type: "string", pattern: "^[a-z0-9][a-z0-9_-]*$", description: "the tab's id, which a tab_panel's tab names" }, label: { type: "string", minLength: 1, description: "the text on the tab" } } }, description: "the tabs, in order" }, default: { type: "string", description: "the id of the tab open first; default the first tab" } }, description: "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } },
8484
8518
  props_tab_panel: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, required: ["tab"], properties: { tab: { type: "string", pattern: "^[a-z0-9][a-z0-9_-]*$", description: "the id of the tab (in the enclosing tabs) this panel belongs to" } }, description: "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } },
8485
8519
  props_select: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, props: { type: "object", additionalProperties: false, properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, options: { type: "array", items: { type: "object", additionalProperties: false, required: ["value", "label"], properties: { value: { type: "string", minLength: 1, description: "what is stored" }, label: { type: "string", description: "what the reader sees" } } }, description: "the options; when absent they are the page param's values (param mode), else the source rows" }, option_value: { type: "string", description: "with a source: the row column that is stored; default id" }, option_label: { type: "string", description: "with a source: the row column the reader sees; default the value column" }, value: { type: "string", description: "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, label: { type: "string", description: "the control's label; default the page param's label (param mode), else the element's label" }, placeholder: { type: "string", description: "what the control says before a choice; default Choose\u2026" } }, description: "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } },
8486
8520
  props_date_picker: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, mode: { enum: ["date", "month"], description: "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, value: { type: "string", pattern: "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", description: "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, label: { type: "string", description: "the control's label; default the page param's label (param mode), else the element's label" }, placeholder: { type: "string", description: "what the control says before a pick; default Pick a date / Pick a month" } }, description: "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } },
8487
- props_data_grid: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose rows the grid shows" }, props: { type: "object", additionalProperties: false, required: ["columns"], properties: { columns: { type: "array", minItems: 1, items: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the row key the column shows" }, label: { type: "string", description: "the header; default the field, humanised" }, format: { enum: ["currency", "number", "percent", "text", "date"], description: "how the value reads; default text" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, align: { enum: ["start", "end"], description: "default end for currency, number and percent, start otherwise" }, sortable: { type: "boolean", description: "whether the header sorts; default true" } } }, description: "the columns, in order" }, key: { type: "string", description: "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, page_size: { type: "integer", minimum: 5, description: "rows per page; default 10" }, sort: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the column sorted first" }, dir: { enum: ["asc", "desc"], description: "default asc" } }, description: "the order the rows start in; default the order the handler answered" }, on_row: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*$", description: "a handler called with {row} when a reader opens a row; the page re-reads after it" }, row_actions: { type: "array", minItems: 1, items: { oneOf: [{ type: "object", additionalProperties: false, required: ["label", "dialog"], properties: { label: { type: "string", minLength: 1, description: "the text on the row's button" }, dialog: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_-]*$", description: "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, role: { type: "string", minLength: 1, description: "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { type: "object", additionalProperties: false, required: ["label", "call"], properties: { label: { type: "string", minLength: 1, description: "the text on the row's button" }, call: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*$", description: "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, confirm: { type: "string", minLength: 1, description: "the question asked before the call runs (Confirm / Cancel); default none" }, role: { type: "string", minLength: 1, description: "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, description: "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, empty_text: { type: "string", description: "what the empty state says; default the registry's sentence, Nothing to show." } }, description: "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } },
8521
+ props_data_grid: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose rows the grid shows" }, props: { type: "object", additionalProperties: false, required: ["columns"], properties: { columns: { type: "array", minItems: 1, items: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the row key the column shows" }, label: { type: "string", description: "the header; default the field, humanised" }, format: { anyOf: [{ enum: ["currency", "number", "percent", "text", "date"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "how the value reads; default text" }, negative: { enum: ["minus", "red_minus", "absolute", "red_absolute"], description: "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, align: { enum: ["start", "end"], description: "default end for currency, number and percent, start otherwise" }, sortable: { type: "boolean", description: "whether the header sorts; default true" } } }, description: "the columns, in order" }, key: { type: "string", description: "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, page_size: { type: "integer", minimum: 5, description: "rows per page; default 10" }, sort: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the column sorted first" }, dir: { enum: ["asc", "desc"], description: "default asc" } }, description: "the order the rows start in; default the order the handler answered" }, on_row: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*$", description: "a handler called with {row} when a reader opens a row; the page re-reads after it" }, row_actions: { type: "array", minItems: 1, items: { oneOf: [{ type: "object", additionalProperties: false, required: ["label", "dialog"], properties: { label: { type: "string", minLength: 1, description: "the text on the row's button" }, dialog: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_-]*$", description: "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, role: { type: "string", minLength: 1, description: "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { type: "object", additionalProperties: false, required: ["label", "call"], properties: { label: { type: "string", minLength: 1, description: "the text on the row's button" }, call: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*$", description: "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, confirm: { type: "string", minLength: 1, description: "the question asked before the call runs (Confirm / Cancel); default none" }, role: { type: "string", minLength: 1, description: "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, description: "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, empty_text: { type: "string", description: "what the empty state says; default the registry's sentence, Nothing to show." } }, description: "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } },
8488
8522
  props_dialog: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, properties: { trigger: { type: "string", minLength: 1, description: "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, title: { type: "string", description: "the dialog's title; default the element's label" }, description: { type: "string", description: "one line under the title" }, confirm: { type: "string", description: "the text on the confirm button; default Confirm" }, on_confirm: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*$", description: "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, values_from: { enum: ["row"], description: "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, key: { type: "string", minLength: 1, description: "with values_from row: the row column posted as id; default the grid's key, else id" } }, description: "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } },
8489
- props_variance_table: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose rows are the lines" }, props: { type: "object", additionalProperties: false, required: ["row", "actual", "plan"], properties: { row: { type: "string", minLength: 1, description: "the column naming each line; its value is the line's data-dr-row" }, actual: { type: "string", minLength: 1, description: "the column holding the actual figure" }, plan: { type: "string", minLength: 1, description: "the column holding the plan (budget) figure" }, format: { enum: ["currency", "number", "percent"], description: "how actual, plan and variance read; default currency" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, favorable: { enum: ["higher", "lower"], description: "which way is good: higher (the default) for revenue, lower for cost" }, threshold: { type: "object", additionalProperties: false, required: [], properties: { abs: { type: "number", minimum: 0, description: "a variance smaller than this, in the figures' units, is neutral" }, pct: { type: "number", minimum: 0, description: "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, description: "below both limits a variance is neutral rather than toned; default none" }, empty_text: { type: "string", description: "what the empty state says; default the registry's sentence, Nothing to show." } }, description: "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } },
8523
+ props_variance_table: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler whose rows are the lines" }, props: { type: "object", additionalProperties: false, required: ["row", "actual", "plan"], properties: { row: { type: "string", minLength: 1, description: "the column naming each line; its value is the line's data-dr-row" }, actual: { type: "string", minLength: 1, description: "the column holding the actual figure" }, plan: { type: "string", minLength: 1, description: "the column holding the plan (budget) figure" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "how actual, plan and variance read; default currency" }, negative: { enum: ["minus", "red_minus", "absolute", "red_absolute"], description: "how actual, plan and variance read below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, favorable: { enum: ["higher", "lower"], description: "which way is good: higher (the default) for revenue, lower for cost" }, threshold: { type: "object", additionalProperties: false, required: [], properties: { abs: { type: "number", minimum: 0, description: "a variance smaller than this, in the figures' units, is neutral" }, pct: { type: "number", minimum: 0, description: "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, description: "below both limits a variance is neutral rather than toned; default none" }, empty_text: { type: "string", description: "what the empty state says; default the registry's sentence, Nothing to show." } }, description: "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } },
8490
8524
  props_toggle: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, value: { type: "boolean", description: "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, label: { type: "string", description: "the switch's label; default the page param's label (param mode), else the element's label" }, description: { type: "string", description: "one line under the label" } }, description: "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } },
8491
8525
  props_control_group: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, properties: { columns: { enum: [1, 2, 3, 4], description: "how many controls sit side by side; default 1 (under 640px always 1)" }, label_position: { enum: ["top", "start"], description: "top (the default): each label above its control; start: every label in one column before its control" }, description: { type: "string", description: "one line above the controls" } }, description: "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } },
8492
8526
  props_callout: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, props: { type: "object", additionalProperties: false, required: ["rules"], properties: { rules: { type: "array", minItems: 1, items: { type: "object", additionalProperties: false, required: ["when", "tone", "text"], properties: { when: { oneOf: [{ type: "object", additionalProperties: false, required: ["path", "gte"], properties: { path: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", description: "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, gte: { type: "number", description: "matches when the value is at least this" } } }, { type: "object", additionalProperties: false, required: ["path", "lte"], properties: { path: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", description: "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, lte: { type: "number", description: "matches when the value is at most this" } } }, { type: "object", additionalProperties: false, required: ["path", "eq"], properties: { path: { type: "string", pattern: "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", description: "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, eq: { type: ["string", "number", "boolean"], description: "matches when the value is exactly this" } } }], description: "the condition: one path and one of gte, lte, eq" }, tone: { enum: ["positive", "neutral", "warning", "negative"], description: "the callout's tone" }, text: { type: "string", minLength: 1, description: "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, description: "tried in order; the first whose when holds is the sentence" }, default: { type: "object", additionalProperties: false, required: ["tone", "text"], properties: { tone: { enum: ["positive", "neutral", "warning", "negative"], description: "the callout's tone" }, text: { type: "string", minLength: 1, description: "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, description: "what it says when no rule holds; default nothing" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" } }, description: "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } },
8493
- props_scenario_columns: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, props: { type: "object", additionalProperties: false, required: ["key", "label_field", "metrics"], properties: { key: { type: "string", minLength: 1, description: "the column naming each row uniquely; its value is the column's data-dr-row" }, label_field: { type: "string", minLength: 1, description: "the column whose value heads each scenario's column" }, metrics: { type: "array", minItems: 1, items: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the row column the line shows" }, label: { type: "string", description: "the line's name; default the field, humanised" }, format: { enum: ["currency", "number", "percent"], description: "how the value reads" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, favorable: { enum: ["higher", "lower"], description: "which way is good for the delta's tone: higher (the default) or lower" } } }, description: "the lines, in order" }, max: { type: "integer", minimum: 1, description: "how many rows may be ticked at once; default 3 (at most 6)" }, baseline: { type: "string", minLength: 1, description: "the key value of the row every delta is against; default the first row" }, empty_text: { type: "string", description: "what the empty state says; default the registry's sentence, Nothing to show." } }, description: "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } },
8494
- props_slider: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this slider writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this slider reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, min: { type: "number", description: "the track's low end, in stored units; default the page param's min (param mode), else 0" }, max: { type: "number", description: "the track's high end, in stored units; default the page param's max (param mode). Required one way or the other: a slider with neither draws its 'slider needs a max' panel (1.0.1) and the compiler refuses it (part_bounds)" }, step: { type: "number", description: "the increment the value moves by, in stored units; every value set is a multiple of it from min; default the page param's step, else 1" }, format: { enum: ["currency", "number", "percent"], description: "how the value beside the track reads; default number" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, show_value: { type: "boolean", description: "whether the formatted value is drawn beside the track; default true" }, marks: { type: "array", items: { type: "object", additionalProperties: false, required: ["value"], properties: { value: { type: "number", description: "where the mark sits, in stored units" }, label: { type: "string", description: "what the mark says; default the value, formatted" } } }, description: "labelled ticks under the track" }, value: { type: "number", description: "field mode: the value it starts on; default min. Param mode reads ctx.params instead" }, label: { type: "string", description: "the slider's label; default the page param's label (param mode), else the element's label" } }, description: "data-dr-props: the slider part's typed props, handed to it as PartProps.props" } } }
8527
+ props_scenario_columns: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, source: { type: "string", description: "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, props: { type: "object", additionalProperties: false, required: ["key", "label_field", "metrics"], properties: { key: { type: "string", minLength: 1, description: "the column naming each row uniquely; its value is the column's data-dr-row" }, label_field: { type: "string", minLength: 1, description: "the column whose value heads each scenario's column" }, metrics: { type: "array", minItems: 1, items: { type: "object", additionalProperties: false, required: ["field"], properties: { field: { type: "string", minLength: 1, description: "the row column the line shows" }, label: { type: "string", description: "the line's name; default the field, humanised" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "how the value reads" }, negative: { enum: ["minus", "red_minus", "absolute", "red_absolute"], description: "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, favorable: { enum: ["higher", "lower"], description: "which way is good for the delta's tone: higher (the default) or lower" } } }, description: "the lines, in order" }, max: { type: "integer", minimum: 1, description: "how many rows may be ticked at once; default 3 (at most 6)" }, baseline: { type: "string", minLength: 1, description: "the key value of the row every delta is against; default the first row" }, empty_text: { type: "string", description: "what the empty state says; default the registry's sentence, Nothing to show." } }, description: "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } },
8528
+ props_slider: { type: "object", additionalProperties: false, required: ["props"], properties: { id: { type: "string", description: "data-dr-id: the element's stable id, unique on its page" }, label: { type: "string", description: "data-dr-label: the title a reader sees" }, role: { type: "string", description: "data-dr-role: the app role this element is meant for; absent means every role" }, span: { type: "integer", description: "data-dr-span: columns of the kit's twelve" }, section: { type: "string", description: "the page section the element sits in (the nearest data-dr-section)" }, props: { type: "object", additionalProperties: false, properties: { field: { type: "string", pattern: "^[a-z][a-z0-9_]*$", description: "field mode: the payload key this slider writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, param: { type: "string", minLength: 1, description: "param mode: the page param (pages[].params[].name) this slider reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, min: { type: "number", description: "the track's low end, in stored units; default the page param's min (param mode), else 0" }, max: { type: "number", description: "the track's high end, in stored units; default the page param's max (param mode). Required one way or the other: a slider with neither draws its 'slider needs a max' panel (1.0.1) and the compiler refuses it (part_bounds)" }, step: { type: "number", description: "the increment the value moves by, in stored units; every value set is a multiple of it from min; default the page param's step, else 1" }, format: { anyOf: [{ enum: ["currency", "number", "percent"] }, { type: "string", maxLength: 64, pattern: "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", description: "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], description: "how the value beside the track reads; default number" }, scale: { enum: ["units", "fraction"], description: "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, currency: { type: "string", pattern: "^[A-Z]{3}$", description: "currency only: the ISO code; default USD" }, show_value: { type: "boolean", description: "whether the formatted value is drawn beside the track; default true" }, marks: { type: "array", items: { type: "object", additionalProperties: false, required: ["value"], properties: { value: { type: "number", description: "where the mark sits, in stored units" }, label: { type: "string", description: "what the mark says; default the value, formatted" } } }, description: "labelled ticks under the track" }, value: { type: "number", description: "field mode: the value it starts on; default min. Param mode reads ctx.params instead" }, label: { type: "string", description: "the slider's label; default the page param's label (param mode), else the element's label" } }, description: "data-dr-props: the slider part's typed props, handed to it as PartProps.props" } } }
8495
8529
  }
8496
8530
  };
8497
8531
 
@@ -9741,12 +9775,12 @@ function checkVocabulary(doc, kind, problems) {
9741
9775
  });
9742
9776
  }
9743
9777
  const format = props["format"];
9744
- if (type === "chart" && format !== void 0 && !CHART_FORMATS3.includes(String(format))) {
9778
+ if (type === "chart" && format !== void 0 && !isNumberFormat2(format)) {
9745
9779
  problems.push({
9746
9780
  code: "vocabulary",
9747
9781
  pointer: pointer("elements", uid, "props", "format"),
9748
9782
  message: `${JSON.stringify(format)} is not a format a chart's numbers read in.`,
9749
- fix: `Use one of ${CHART_FORMATS3.join(", ")}, or omit it: a decimal y reads as currency, any other number as a number.`
9783
+ fix: `Use one of ${CHART_FORMATS3.join(", ")}, a platform format string with a digit placeholder (#,###, $#,###.#[kilo]k), or omit it: a decimal y reads as currency, any other number as a number.`
9750
9784
  });
9751
9785
  }
9752
9786
  }
@@ -12653,11 +12687,78 @@ function openToEveryRole(contract) {
12653
12687
  return out;
12654
12688
  }
12655
12689
 
12690
+ // ../flows/insights-builder/kit/contract/platformPalette.mjs
12691
+ var PLATFORM_CHART = Object.freeze([
12692
+ "#008aff",
12693
+ "#91e7e7",
12694
+ "#f37789",
12695
+ "#ffdc65",
12696
+ "#0e569d",
12697
+ "#bbe0ff",
12698
+ "#57b2ff",
12699
+ "#5ecfb9",
12700
+ "#c7ffda",
12701
+ "#179ab9"
12702
+ ]);
12703
+ var APP_CHART_ORDER = Object.freeze([
12704
+ "#008aff",
12705
+ // 3.45:1, the platform's first colour, still series 1 (Actuals)
12706
+ "#0e569d",
12707
+ // 7.40:1, Forecast (`--dr-series-forecast`)
12708
+ "#179ab9",
12709
+ // 3.30:1
12710
+ "#f37789",
12711
+ // 2.69:1
12712
+ "#57b2ff",
12713
+ // 2.28:1
12714
+ "#91e7e7",
12715
+ // 1.42:1
12716
+ "#bbe0ff",
12717
+ // 1.38:1
12718
+ "#5ecfb9",
12719
+ // 1.89:1, held at 8: the variance colour (`colors[7]`)
12720
+ "#ffdc65",
12721
+ // 1.34:1
12722
+ "#c7ffda"
12723
+ // 1.12:1
12724
+ ]);
12725
+ var APP_FORECAST = "var(--dr-chart-2)";
12726
+ var PALETTE_FILE = "ui/dr-palette.css";
12727
+ function paletteTokens() {
12728
+ const tokens = {};
12729
+ APP_CHART_ORDER.forEach((colour, i) => {
12730
+ tokens[`--dr-chart-${i + 1}`] = colour;
12731
+ });
12732
+ tokens["--dr-series-forecast"] = APP_FORECAST;
12733
+ return tokens;
12734
+ }
12735
+ function paletteCss() {
12736
+ const lines = [
12737
+ "/* The platform's chart palette, in the order a compiled app draws it.",
12738
+ " * GENERATED by compileApp.mjs (contract/platformPalette.mjs): do not edit;",
12739
+ " * an app's own colours go in app.theme (ui/theme.css), which wins over this.",
12740
+ " * The ten DEFAULT_USER_COLORS of vendor/dr-tokens@1.0.0, unchanged, reordered",
12741
+ " * so the lead series clear 3:1 on the white card. An org palette, written",
12742
+ " * inline on <html> by dr-app-runtime, still replaces them.",
12743
+ " */",
12744
+ ":root {"
12745
+ ];
12746
+ for (const [token, value] of Object.entries(paletteTokens())) lines.push(` ${token}: ${value};`);
12747
+ lines.push("}");
12748
+ return `${lines.join("\n")}
12749
+ `;
12750
+ }
12751
+ function isPlatformChartColour(n, value) {
12752
+ const colour = String(value ?? "").trim().toLowerCase();
12753
+ return colour !== "" && (PLATFORM_CHART[n - 1] === colour || APP_CHART_ORDER[n - 1] === colour);
12754
+ }
12755
+
12656
12756
  // ../flows/insights-builder/kit/contract/compileApp.mjs
12657
- var RUNTIME = "dr-app-runtime@1.6.2";
12658
- var UI_KIT2 = "ui-kit/v3";
12757
+ var RUNTIME = "dr-app-runtime@1.7.1";
12758
+ var UI_KIT2 = "ui-kit/v4";
12659
12759
  var CHARTS = "echarts@5.6.0";
12660
- var FMT = "dr-fmt@1.0.0";
12760
+ var FMT = "dr-fmt@2.0.1";
12761
+ var TOKENS = "dr-tokens@1.0.0";
12661
12762
  var WIDGETS = "dr-app-widgets@1.1.0";
12662
12763
  var COMPONENTS = "dr-components@1.1.1";
12663
12764
  var CONTROLS = "dr-components-controls@1.0.1";
@@ -12765,7 +12866,7 @@ var HANDLER_KEYS = [
12765
12866
  "measures",
12766
12867
  "requiresRole"
12767
12868
  ];
12768
- var ATTR_ORDER = ["component", "id", "entity", "action", "source", "field", "filter", "param", "measure", "kind", "x", "y", "series", "format", "module", "args", "props", "declares", "when", "role", "label", "tone"];
12869
+ var ATTR_ORDER = ["component", "id", "entity", "action", "source", "field", "filter", "param", "measure", "kind", "x", "y", "series", "format", "negative", "module", "args", "props", "declares", "when", "role", "label", "tone"];
12769
12870
  var ENTITY_WRITERS2 = /* @__PURE__ */ new Set(["form", "list", "queue", "detail", "filter"]);
12770
12871
  var DECIMAL_TYPES = /* @__PURE__ */ new Set(["decimal", "numeric", "money"]);
12771
12872
  var NUMBER_TYPES = /* @__PURE__ */ new Set(["decimal", "numeric", "money", "int", "integer", "bigint", "float"]);
@@ -13160,7 +13261,7 @@ function themeProblems(app) {
13160
13261
  }
13161
13262
  }
13162
13263
  if (theme.preset !== void 0 && !THEME_PRESETS.includes(theme.preset)) {
13163
- out.push(refuse("preset", `app.theme.preset is ${JSON.stringify(theme.preset)}; the ui-kit this compiler pins (${UI_KIT2}) carries ${either3(THEME_PRESETS)}${theme.preset === "presentation" ? " \u2014 presentation is ui-kit v4's, which is not on the shelf yet" : ""}`));
13264
+ out.push(refuse("preset", `app.theme.preset is ${JSON.stringify(theme.preset)}; the ui-kit this compiler pins (${UI_KIT2}) carries ${either3(THEME_PRESETS)}${theme.preset === "presentation" ? " \u2014 presentation was planned for ui-kit v4, which shipped without it" : ""}`));
13164
13265
  }
13165
13266
  if (theme.density !== void 0 && !THEME_DENSITIES.includes(theme.density)) out.push(refuse("density", `app.theme.density is ${JSON.stringify(theme.density)}; it is ${either3(THEME_DENSITIES)}`));
13166
13267
  return out;
@@ -13566,6 +13667,8 @@ function compileApp(contract, { kit = null, runtime = RUNTIME, extra = {} } = {}
13566
13667
  if (tree.problems.length === 0) problems.push(...modelProblems(declared, tree, handlers, model, rolesOf2(contract.backend?.roles, model), sources));
13567
13668
  if (tree.problems.length === 0) problems.push(...historyProblems(declared, tree, handlers, model));
13568
13669
  if (tree.problems.length === 0) problems.push(...chartProblems(declared, tree, handlers, model));
13670
+ problems.push(...numberProblems(declared));
13671
+ problems.push(...numberPinProblems(declared, { "dr-app-runtime": runtime, "dr-app-widgets": appWidgets, "dr-components": appComponents, "dr-components-controls": appControls }));
13569
13672
  if (tree.problems.length === 0) problems.push(...widgetProblems(declared, tree, handlers, contract?.data?.sources));
13570
13673
  if (tree.problems.length === 0) problems.push(...partProblems(declared, tree, handlers, sources, contract?.pages, model));
13571
13674
  if (problems.length > 0) return { files: {}, problems, contract };
@@ -13593,9 +13696,10 @@ function compileApp(contract, { kit = null, runtime = RUNTIME, extra = {} } = {}
13593
13696
  for (const name of served) files[`handlers/${name}.py`] = sourceModule(name, sources, transforms, params);
13594
13697
  const theme = isPlainObject7(app.theme) ? app.theme : null;
13595
13698
  if (theme !== null) files[THEME_FILE4] = themeCss(theme);
13699
+ files[PALETTE_FILE] = paletteCss();
13596
13700
  for (const page of pages) {
13597
13701
  if (page.owned === true) continue;
13598
- files[page.path] = pageHtml(whole, page, elements, tree, model, { runtime, uiKit, charts, fmt, appWidgets, appComponents, appControls, theme: theme !== null });
13702
+ files[page.path] = pageHtml(whole, page, elements, tree, model, { runtime, uiKit, charts, fmt, appWidgets, appComponents, appControls, theme: theme !== null, extra });
13599
13703
  }
13600
13704
  if (typeof extra["seed.json"] === "string") files["seed.json"] = extra["seed.json"];
13601
13705
  files["tests.json"] = typeof extra["tests.json"] === "string" ? extra["tests.json"] : json(testsOf(handlers, names, sources, served));
@@ -14301,6 +14405,54 @@ function historyProblems(elements, tree, handlers, model) {
14301
14405
  return problems;
14302
14406
  }
14303
14407
  var CHART_SOURCE_ROLES = ["list", "inbox", "custom"];
14408
+ var NUMBER_ELEMENTS = Object.freeze(["stat", "chart", "widget"]);
14409
+ function numberProblems(elements) {
14410
+ const problems = [];
14411
+ for (const uid of Object.keys(elements).sort(natural)) {
14412
+ const element = elements[uid] ?? {};
14413
+ if (!NUMBER_ELEMENTS.includes(element.type)) continue;
14414
+ const props = element.props ?? {};
14415
+ const say = (key, message) => problems.push({ code: "number_format", pointer: `/elements/${escapePointer3(uid)}/props/${key}`, message: `${element.type} "${uid}" ${message}` });
14416
+ if (element.type !== "chart" && props.format !== void 0 && props.format !== null && !isNumberFormat(props.format)) {
14417
+ say(
14418
+ "format",
14419
+ `states format ${JSON.stringify(props.format)}; use ${either3(CHART_FORMATS2)}, or a platform format string with a digit placeholder (${FORMAT_PATTERNS2.number}, ${FORMAT_PATTERNS2.currency}, #,###.#[kilo]k, #,###;[Red](#,###))`
14420
+ );
14421
+ }
14422
+ if (props.negative !== void 0 && props.negative !== null && !NEGATIVE_MODES2.includes(props.negative)) {
14423
+ say("negative", `states negative ${JSON.stringify(props.negative)}; it is the platform's negative-number mode: ${either3(NEGATIVE_MODES2)}`);
14424
+ }
14425
+ }
14426
+ return problems;
14427
+ }
14428
+ function numberPinProblems(elements, pins) {
14429
+ const problems = [];
14430
+ for (const uid of Object.keys(elements).sort(natural)) {
14431
+ const element = elements[uid] ?? {};
14432
+ if (element.type === "custom") continue;
14433
+ const module = MODULE_OF2[element.type];
14434
+ const pin = pins[module];
14435
+ if (typeof pin !== "string" || drawsPlatformNumbers(pin)) continue;
14436
+ const need = typeof PLATFORM_NUMBERS2[module] === "string" ? `${module}@${PLATFORM_NUMBERS2[module]}` : `a ${module} release that draws it`;
14437
+ const walk4 = (node, at) => {
14438
+ if (Array.isArray(node)) return node.forEach((child, i) => walk4(child, `${at}/${i}`));
14439
+ if (!isPlainObject7(node)) return;
14440
+ for (const [key, value] of Object.entries(node)) {
14441
+ const pointer2 = `${at}/${escapePointer3(key)}`;
14442
+ const say = (what) => problems.push({
14443
+ code: "number_unsupported",
14444
+ pointer: pointer2,
14445
+ message: `${element.type} "${uid}" states ${what}, and ${what.split(" ")[0]} needs ${need}; the pinned version is ${pin.slice(pin.lastIndexOf("@") + 1)}, which draws only ${either3(CHART_FORMATS2)} \u2014 use one of those words for now, and drop negative`
14446
+ });
14447
+ if (key === "format" && isPlatformFormat(value)) say(`format ${JSON.stringify(value)}`);
14448
+ else if (key === "negative" && value !== void 0 && value !== null) say(`negative ${JSON.stringify(value)}`);
14449
+ else walk4(value, pointer2);
14450
+ }
14451
+ };
14452
+ walk4(element.props ?? {}, `/elements/${escapePointer3(uid)}/props`);
14453
+ }
14454
+ return problems;
14455
+ }
14304
14456
  function chartProblems(elements, tree, handlers, model) {
14305
14457
  const problems = [];
14306
14458
  for (const uid of Object.keys(elements).sort(natural)) {
@@ -14327,8 +14479,11 @@ function chartProblems(elements, tree, handlers, model) {
14327
14479
  if (stated(props.series) && (props.series === props.x || props.series === props.y)) {
14328
14480
  say("series", `splits its lines by "${props.series}", which is already its ${props.series === props.x ? "x" : "y"}; series is a third column whose distinct values are one line each \u2014 drop it for one line`);
14329
14481
  }
14330
- if (props.format !== void 0 && props.format !== null && !CHART_FORMATS2.includes(props.format)) {
14331
- say("format", `states format ${JSON.stringify(props.format)}; use ${either3(CHART_FORMATS2)}, or omit it to read the number off y's column (currency for a decimal)`);
14482
+ if (props.format !== void 0 && props.format !== null && !isNumberFormat(props.format)) {
14483
+ say(
14484
+ "format",
14485
+ `states format ${JSON.stringify(props.format)}; use ${either3(CHART_FORMATS2)}, a platform format string with a digit placeholder (${FORMAT_PATTERNS2.number}, ${FORMAT_PATTERNS2.currency}, #,###.#[kilo]k), or omit it to read the number off y's column (currency for a decimal)`
14486
+ );
14332
14487
  }
14333
14488
  if (!stated(props.source)) {
14334
14489
  say("source", 'names no source; a chart names the handler that answers its rows with source \u2014 a list, an inbox, or a custom handler answering {"rows": [...]}');
@@ -16134,7 +16289,7 @@ function testCase(name, row) {
16134
16289
  return null;
16135
16290
  }
16136
16291
  }
16137
- function pageHtml(contract, page, elements, tree, model, { runtime, uiKit, charts, fmt, appWidgets, appComponents, appControls, theme = false }) {
16292
+ function pageHtml(contract, page, elements, tree, model, { runtime, uiKit, charts, fmt, appWidgets, appComponents, appControls, theme = false, extra = {} }) {
16138
16293
  const app = contract.app ?? {};
16139
16294
  const name = named4(app.name) ? app.name : named4(app.id) ? app.id : "";
16140
16295
  const title = documentTitle(page, name);
@@ -16171,6 +16326,16 @@ function pageHtml(contract, page, elements, tree, model, { runtime, uiKit, chart
16171
16326
  `<main data-dr-app data-dr-page="${attr2(page.path)}">`,
16172
16327
  ...skeleton,
16173
16328
  "</main>",
16329
+ // P1/P1b stylesheets, in the body after </main> for the reason the
16330
+ // scripts are: a line in the head would move every skeleton line, and
16331
+ // the uids with them. Nothing they style is drawn before the runtime
16332
+ // below mounts, so there is no flash. The reordered platform palette
16333
+ // (`platformPalette.mjs`) declares on :root after ui-kit/v4's, so it
16334
+ // moves v4's order; an app theme declares on the body, so it still
16335
+ // wins, as an org palette (inline on <html>) does. The icon font only
16336
+ // on a page that draws a `dr-icon-*`.
16337
+ `<link rel="stylesheet" href="./${PALETTE_FILE.slice("ui/".length)}">`,
16338
+ ...iconsOn(page, elements, extra) ? [`<link rel="stylesheet" href="${CLIMB}vendor/${TOKENS}/icons/dr-icons.css">`] : [],
16174
16339
  ...chartScripts(page, elements, { charts, fmt }),
16175
16340
  `<script src="${CLIMB}vendor/${runtime}/runtime.js"></script>`,
16176
16341
  ...widgets.length > 0 ? [`<script src="${CLIMB}vendor/${appWidgets}/widgets.js"></script>`] : [],
@@ -16187,9 +16352,19 @@ function chartScripts(page, elements, { charts, fmt }) {
16187
16352
  const echarts = draws || widgets.some((element) => !DOM_KINDS.has(element.props?.kind));
16188
16353
  const out = [];
16189
16354
  if (echarts) out.push(`<script src="${CLIMB}vendor/${charts}/echarts.min.js"></script>`);
16190
- if (echarts || widgets.length > 0) out.push(`<script src="${CLIMB}vendor/${fmt}/fmt.js"></script>`);
16355
+ if (echarts || widgets.length > 0 || platformNumbersOn(page, elements)) out.push(`<script src="${CLIMB}vendor/${fmt}/fmt.js"></script>`);
16191
16356
  return out;
16192
16357
  }
16358
+ function platformNumbersOn(page, elements) {
16359
+ const states = (node) => {
16360
+ if (Array.isArray(node)) return node.some(states);
16361
+ if (!isPlainObject7(node)) return false;
16362
+ return Object.entries(node).some(
16363
+ ([key, value]) => key === "format" && isPlatformFormat(value) || key === "negative" && NEGATIVE_MODES2.includes(value) || states(value)
16364
+ );
16365
+ };
16366
+ return Object.values(elements).some((element) => element?.page === page.path && states(element.props));
16367
+ }
16193
16368
  function componentScripts(page, elements, { appComponents, appControls }) {
16194
16369
  const pins = { "dr-components": appComponents, "dr-components-controls": appControls };
16195
16370
  const used = /* @__PURE__ */ new Set();
@@ -16212,6 +16387,17 @@ var DOM_KINDS = /* @__PURE__ */ new Set(["kpi", "table", "narrative"]);
16212
16387
  function widgetsOn(page, elements) {
16213
16388
  return Object.keys(elements).sort(natural).map((uid) => elements[uid]).filter((element) => element?.page === page.path && element.type === "widget");
16214
16389
  }
16390
+ var ICON_RE = /(^|[^a-z0-9-])dr-icon-[a-z0-9]/;
16391
+ function iconsOn(page, elements, extra) {
16392
+ for (const element of Object.values(elements)) {
16393
+ if (element?.page !== page.path) continue;
16394
+ if (ICON_RE.test(JSON.stringify(element.props ?? {}))) return true;
16395
+ if (element.type !== "custom" || !named4(element.props?.module)) continue;
16396
+ const source = extra[`ui/${element.props.module}`];
16397
+ if (typeof source === "string" && ICON_RE.test(source)) return true;
16398
+ }
16399
+ return false;
16400
+ }
16215
16401
  function moduleScripts(page, elements) {
16216
16402
  const modules = /* @__PURE__ */ new Set();
16217
16403
  for (const element of Object.values(elements)) {
@@ -17214,11 +17400,14 @@ var CONTRAST_RULES = [
17214
17400
  ["--dr-chart-6", 3, "chart series 6"],
17215
17401
  ["--dr-chart-7", 3, "chart series 7"],
17216
17402
  ["--dr-chart-8", 3, "chart series 8"],
17403
+ // ui-kit/v4 draws ten series (the platform's ten).
17404
+ ["--dr-chart-9", 3, "chart series 9"],
17405
+ ["--dr-chart-10", 3, "chart series 10"],
17217
17406
  ["--dr-border", 1.3, "the card border"]
17218
17407
  ];
17219
17408
  var FLOORS = new Map(CONTRAST_RULES.map(([token, floor, what]) => [token, { floor, what }]));
17220
17409
  function checkTheme(app) {
17221
- const violations = [];
17410
+ const violations = [...paletteFileViolations(app)];
17222
17411
  const file = app.ui.find((entry) => entry.path === THEME_FILE5);
17223
17412
  if (!file) return { violations };
17224
17413
  const overrides = rootTokens(file.text);
@@ -17239,6 +17428,8 @@ function checkTheme(app) {
17239
17428
  if (!rule) continue;
17240
17429
  const value = resolve6(token, overrides);
17241
17430
  if (value === null) continue;
17431
+ const series = /^--dr-chart-(\d+)$/.exec(token);
17432
+ if (series && isPlatformChartColour(Number(series[1]), value)) continue;
17242
17433
  const ratio = contrast(rgbOf2(value, ground), ground);
17243
17434
  if (ratio === null) {
17244
17435
  violations.push({
@@ -17259,6 +17450,20 @@ function checkTheme(app) {
17259
17450
  }
17260
17451
  return { violations: dedupe2(violations) };
17261
17452
  }
17453
+ function paletteFileViolations(app) {
17454
+ const file = app.ui.find((entry) => entry.path === PALETTE_FILE);
17455
+ if (!file) return [];
17456
+ const stated2 = rootTokens(file.text);
17457
+ const expected = paletteTokens();
17458
+ const out = [];
17459
+ const say = (line, message) => out.push({ rule: "R2.8", where: `${PALETTE_FILE}:${line}`, message });
17460
+ for (const [token, { value, line }] of stated2) {
17461
+ if (!(token in expected)) say(line, `${PALETTE_FILE} declares ${token}, which the compiler never writes there; the file is generated \u2014 put an app's own colours in app.theme (ui/theme.css)`);
17462
+ else if (value.toLowerCase() !== expected[token]) say(line, `${PALETTE_FILE} sets ${token} to ${value}, and the compiler writes ${expected[token]}; the file is generated \u2014 put an app's own colours in app.theme (ui/theme.css), where R2.8 measures them`);
17463
+ }
17464
+ for (const token of Object.keys(expected)) if (!stated2.has(token)) say(1, `${PALETTE_FILE} is missing ${token}; the file is generated \u2014 recompile rather than edit it`);
17465
+ return out;
17466
+ }
17262
17467
  function themesInUse(app) {
17263
17468
  const found = /* @__PURE__ */ new Set();
17264
17469
  for (const page of app.pages) {
@@ -17666,23 +17871,28 @@ function parseAttrs2(raw) {
17666
17871
  }
17667
17872
 
17668
17873
  // ../flows/appspace-builder/kit/contract/components.gen.mjs
17669
- var REGISTRY_VERSION2 = Object.freeze(6);
17874
+ var REGISTRY_VERSION2 = Object.freeze(7);
17670
17875
  var ELEMENT_TYPES3 = Object.freeze(["region", "grid", "widget", "control", "nav", "tab", "slot", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "field", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
17671
17876
  var COMPONENT_TYPES4 = Object.freeze(["widget", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
17672
17877
  var APP_TYPES2 = Object.freeze(["widget", "form", "list", "detail", "queue", "action", "filter", "stat", "chart", "custom", "field", "number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
17673
17878
  var DASHBOARD_TYPES2 = Object.freeze(["region", "grid", "control", "nav", "tab", "slot"]);
17674
- var COMPONENT_ATTRIBUTES3 = Object.freeze(["data-dr-component", "data-dr-entity", "data-dr-action", "data-dr-source", "data-dr-field", "data-dr-param", "data-dr-role", "data-dr-filter", "data-dr-id", "data-dr-label", "data-dr-measure", "data-dr-tone", "data-dr-kind", "data-dr-x", "data-dr-y", "data-dr-series", "data-dr-format", "data-dr-module", "data-dr-args", "data-dr-props", "data-dr-declares"]);
17675
- var COMPONENT_PROPS4 = Object.freeze([["data-dr-entity", "entity"], ["data-dr-action", "action"], ["data-dr-source", "source"], ["data-dr-field", "field"], ["data-dr-param", "param"], ["data-dr-role", "role"], ["data-dr-id", "id"], ["data-dr-label", "label"], ["data-dr-measure", "measure"], ["data-dr-tone", "tone"], ["data-dr-kind", "kind"], ["data-dr-x", "x"], ["data-dr-y", "y"], ["data-dr-series", "series"], ["data-dr-format", "format"], ["data-dr-module", "module"]]);
17879
+ var COMPONENT_ATTRIBUTES3 = Object.freeze(["data-dr-component", "data-dr-entity", "data-dr-action", "data-dr-source", "data-dr-field", "data-dr-param", "data-dr-role", "data-dr-filter", "data-dr-id", "data-dr-label", "data-dr-measure", "data-dr-tone", "data-dr-kind", "data-dr-x", "data-dr-y", "data-dr-series", "data-dr-format", "data-dr-negative", "data-dr-module", "data-dr-args", "data-dr-props", "data-dr-declares"]);
17880
+ var COMPONENT_PROPS4 = Object.freeze([["data-dr-entity", "entity"], ["data-dr-action", "action"], ["data-dr-source", "source"], ["data-dr-field", "field"], ["data-dr-param", "param"], ["data-dr-role", "role"], ["data-dr-id", "id"], ["data-dr-label", "label"], ["data-dr-measure", "measure"], ["data-dr-tone", "tone"], ["data-dr-kind", "kind"], ["data-dr-x", "x"], ["data-dr-y", "y"], ["data-dr-series", "series"], ["data-dr-format", "format"], ["data-dr-negative", "negative"], ["data-dr-module", "module"]]);
17676
17881
  var HANDLER_ROLES3 = Object.freeze(["list", "save", "remove", "submit", "inbox", "decide", "summary", "history", "custom"]);
17677
17882
  var CHART_KINDS5 = Object.freeze(["line", "bar", "area"]);
17678
17883
  var CHART_FORMATS4 = Object.freeze(["currency", "number", "percent"]);
17884
+ var PLATFORM_FORMAT2 = Object.freeze({ "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$" });
17885
+ var NEGATIVE_MODES3 = Object.freeze(["minus", "red_minus", "absolute", "red_absolute"]);
17886
+ var FORMAT_PATTERNS3 = Object.freeze({ "currency": "$#,###", "number": "#,###", "percent": '#,###.#"%"' });
17887
+ var PLATFORM_NUMBERS3 = Object.freeze({ "dr-app-runtime": "1.8.0", "dr-app-widgets": "1.2.0", "dr-components": "1.2.0", "dr-components-controls": "1.1.0" });
17888
+ var MODULE_OF3 = Object.freeze({ "widget": "dr-app-widgets", "form": "dr-app-runtime", "list": "dr-app-runtime", "detail": "dr-app-runtime", "queue": "dr-app-runtime", "action": "dr-app-runtime", "filter": "dr-app-runtime", "stat": "dr-app-runtime", "chart": "dr-app-runtime", "custom": "dr-app-runtime", "field": "dr-app-runtime", "number_input": "dr-components", "tabs": "dr-components", "tab_panel": "dr-components", "select": "dr-components", "date_picker": "dr-components", "data_grid": "dr-components", "dialog": "dr-components", "variance_table": "dr-components", "toggle": "dr-components", "control_group": "dr-components", "callout": "dr-components", "scenario_columns": "dr-components", "slider": "dr-components-controls" });
17679
17889
  var STAT_TONES3 = Object.freeze(["default", "positive", "warning", "negative"]);
17680
17890
  var WIDGET_KINDS4 = Object.freeze(["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"]);
17681
17891
  var KIND_READS4 = Object.freeze({ "line": ["series"], "area": ["series"], "bar": ["series", "breakdown"], "stacked": ["series"], "pie": ["breakdown"], "donut": ["breakdown"], "kpi": ["kpi"], "candle": ["ohlc"], "bubble": ["scatter"], "table": ["table"], "narrative": ["narrative"] });
17682
17892
  var STRICT_TYPES3 = Object.freeze(["number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns", "slider"]);
17683
- var PROPS_SCHEMAS3 = Object.freeze({ "region": { "type": "object", "properties": {} }, "grid": { "type": "object", "properties": {} }, "widget": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the card's title on an app page" }, "role": { "type": "string", "description": "data-dr-role: the app role this card is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "kind": { "enum": ["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"], "description": "data-dr-kind on an app page, the widget kind on a dashboard" }, "source": { "type": "string", "description": "the handler whose payload an app card draws (data-dr-source), or the SPEC key a dashboard card draws" }, "format": { "enum": ["currency", "number", "percent"], "description": "data-dr-format: how the card's numbers read" }, "title": { "type": "string", "description": "a dashboard card's title" }, "subtitle": { "type": "string", "description": "the line under a dashboard card's title" }, "description": { "type": "string", "description": "what a dashboard card shows, in words" }, "params": { "type": "array", "description": "the params a dashboard card honours" } } }, "control": { "type": "object", "properties": { "param": { "type": "string", "description": "the param it moves" }, "control_kind": { "type": "string", "description": "the control's kind" }, "type": { "type": "string", "description": "the input type" }, "min": { "type": "string", "description": "the lowest value" }, "max": { "type": "string", "description": "the highest value" }, "step": { "type": "string", "description": "the step" }, "value": { "type": "string", "description": "the starting value" }, "label": { "type": "string", "description": "the label" } } }, "nav": { "type": "object", "properties": { "aria_label": { "type": "string", "description": "the nav's accessible name" } } }, "tab": { "type": "object", "properties": { "current": { "type": "boolean", "description": "true on the page it names" }, "href": { "type": "string", "description": "the page it links to" }, "label": { "type": "string", "description": "the text it shows" } } }, "slot": { "type": "object", "properties": {} }, "form": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the form writes" }, "action": { "type": "string", "description": "data-dr-action: the handler that saves it" } } }, "list": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table listed" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers the rows" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "detail": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the row is from" }, "action": { "type": "string", "description": "data-dr-action: the handler it acts through" } } }, "queue": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table queued" }, "source": { "type": "string", "description": "data-dr-source: the inbox handler" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "action": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "action": { "type": "string", "description": "data-dr-action: the handler it runs" }, "param": { "type": "string", "description": "data-dr-param: the argument it passes" }, "entity": { "type": "string", "description": "data-dr-entity: the table the handler acts on" } } }, "filter": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "field": { "type": "string", "description": "data-dr-field: the column filtered" }, "entity": { "type": "string", "description": "data-dr-entity: the table filtered" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "stat": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the summary handler" }, "measure": { "type": "string", "description": "data-dr-measure: the key of the number shown" }, "tone": { "type": "string", "description": "data-dr-tone: default | positive | warning | negative" } } }, "chart": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows it draws" }, "kind": { "enum": ["line", "bar", "area"], "description": "data-dr-kind: what it draws" }, "x": { "type": "string", "description": "data-dr-x: the column on the category axis" }, "y": { "type": "string", "description": "data-dr-y: the one numeric column drawn" }, "series": { "type": "string", "description": "data-dr-series: the column whose distinct values are one line each" }, "format": { "enum": ["currency", "number", "percent"], "description": "data-dr-format: how a number reads; percent is a value already in percent units" } } }, "custom": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose answer the module receives" }, "module": { "type": "string", "pattern": "^components/[a-z][a-z0-9_-]*\\.js$", "description": "data-dr-module: the file that draws it" }, "args": { "type": "object", "description": "data-dr-args: one JSON object handed to the module as ui.args; absent means {}" }, "declares": { "type": "object", "description": "data-dr-declares: what the module does, stated for graders and app-space test \u2014 nothing draws from it and the runtime never reads it. Every key is optional; a name it lists must be one the contract declares (custom_declares)", "additionalProperties": false, "properties": { "reads": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the data.sources entries and handlers whose answers it draws" }, "calls": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the handlers it calls through ui.call; app-space test reports a call to any other (custom-undeclared-call)" }, "produces": { "type": "object", "description": `per called handler, the payload keys it sends \u2014 {"project": ["growth", "hires"]}; for a handler it does not list, app-space test reads the keys off the module's ui.call object literal`, "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "shows": { "type": "array", "description": "the numbers it displays; the module projects each one on the element that shows it (data-dr-field, data-dr-value, data-dr-format), which app-space test harvests into the element's values", "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the field the number is, as its data-dr-field names it" }, "format": { "enum": ["currency", "number", "percent"], "description": "how it reads, as its data-dr-format says" }, "scale": { "enum": ["fraction"], "description": "fraction: the value is a share (0.04) shown as a percent (4%)" } } } } } } } }, "field": { "type": "object", "properties": { "entity": { "type": "string", "description": "data-dr-entity: the table the column is in" }, "field": { "type": "string", "description": "data-dr-field: the column" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers its choices" }, "label": { "type": "string", "description": "the field's label" }, "required": { "type": "boolean", "description": "true when the form cannot be saved without it" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "enum": ["currency", "number", "percent"], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent", "text", "date"], "description": "how the value reads; default text" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "enum": ["currency", "number", "percent"], "description": "how actual, plan and variance read; default currency" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent"], "description": "how the value reads" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } }, "slider": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this slider writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this slider reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "min": { "type": "number", "description": "the track's low end, in stored units; default the page param's min (param mode), else 0" }, "max": { "type": "number", "description": "the track's high end, in stored units; default the page param's max (param mode). Required one way or the other: a slider with neither draws its 'slider needs a max' panel (1.0.1) and the compiler refuses it (part_bounds)" }, "step": { "type": "number", "description": "the increment the value moves by, in stored units; every value set is a multiple of it from min; default the page param's step, else 1" }, "format": { "enum": ["currency", "number", "percent"], "description": "how the value beside the track reads; default number" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "show_value": { "type": "boolean", "description": "whether the formatted value is drawn beside the track; default true" }, "marks": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value"], "properties": { "value": { "type": "number", "description": "where the mark sits, in stored units" }, "label": { "type": "string", "description": "what the mark says; default the value, formatted" } } }, "description": "labelled ticks under the track" }, "value": { "type": "number", "description": "field mode: the value it starts on; default min. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the slider's label; default the page param's label (param mode), else the element's label" } }, "description": "data-dr-props: the slider part's typed props, handed to it as PartProps.props" } } } });
17893
+ var PROPS_SCHEMAS3 = Object.freeze({ "region": { "type": "object", "properties": {} }, "grid": { "type": "object", "properties": {} }, "widget": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the card's title on an app page" }, "role": { "type": "string", "description": "data-dr-role: the app role this card is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "kind": { "enum": ["line", "area", "bar", "stacked", "pie", "donut", "kpi", "candle", "bubble", "table", "narrative"], "description": "data-dr-kind on an app page, the widget kind on a dashboard" }, "source": { "type": "string", "description": "the handler whose payload an app card draws (data-dr-source), or the SPEC key a dashboard card draws" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "data-dr-format: how the card's numbers read" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "title": { "type": "string", "description": "a dashboard card's title" }, "subtitle": { "type": "string", "description": "the line under a dashboard card's title" }, "description": { "type": "string", "description": "what a dashboard card shows, in words" }, "params": { "type": "array", "description": "the params a dashboard card honours" } } }, "control": { "type": "object", "properties": { "param": { "type": "string", "description": "the param it moves" }, "control_kind": { "type": "string", "description": "the control's kind" }, "type": { "type": "string", "description": "the input type" }, "min": { "type": "string", "description": "the lowest value" }, "max": { "type": "string", "description": "the highest value" }, "step": { "type": "string", "description": "the step" }, "value": { "type": "string", "description": "the starting value" }, "label": { "type": "string", "description": "the label" } } }, "nav": { "type": "object", "properties": { "aria_label": { "type": "string", "description": "the nav's accessible name" } } }, "tab": { "type": "object", "properties": { "current": { "type": "boolean", "description": "true on the page it names" }, "href": { "type": "string", "description": "the page it links to" }, "label": { "type": "string", "description": "the text it shows" } } }, "slot": { "type": "object", "properties": {} }, "form": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the form writes" }, "action": { "type": "string", "description": "data-dr-action: the handler that saves it" } } }, "list": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table listed" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers the rows" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "detail": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table the row is from" }, "action": { "type": "string", "description": "data-dr-action: the handler it acts through" } } }, "queue": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "entity": { "type": "string", "description": "data-dr-entity: the table queued" }, "source": { "type": "string", "description": "data-dr-source: the inbox handler" }, "filter": { "description": "data-dr-filter, parsed from `col=value` into an object" } } }, "action": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "action": { "type": "string", "description": "data-dr-action: the handler it runs" }, "param": { "type": "string", "description": "data-dr-param: the argument it passes" }, "entity": { "type": "string", "description": "data-dr-entity: the table the handler acts on" } } }, "filter": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "field": { "type": "string", "description": "data-dr-field: the column filtered" }, "entity": { "type": "string", "description": "data-dr-entity: the table filtered" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "stat": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the summary handler" }, "measure": { "type": "string", "description": "data-dr-measure: the key of the number shown" }, "tone": { "type": "string", "description": "data-dr-tone: default | positive | warning | negative" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "data-dr-format: how the figure reads: a word or a platform format string" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" } } }, "chart": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows it draws" }, "kind": { "enum": ["line", "bar", "area"], "description": "data-dr-kind: what it draws" }, "x": { "type": "string", "description": "data-dr-x: the column on the category axis" }, "y": { "type": "string", "description": "data-dr-y: the one numeric column drawn" }, "series": { "type": "string", "description": "data-dr-series: the column whose distinct values are one line each" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "data-dr-format: how a number reads; percent is a value already in percent units" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "data-dr-negative: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" } } }, "custom": { "type": "object", "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose answer the module receives" }, "module": { "type": "string", "pattern": "^components/[a-z][a-z0-9_-]*\\.js$", "description": "data-dr-module: the file that draws it" }, "args": { "type": "object", "description": "data-dr-args: one JSON object handed to the module as ui.args; absent means {}" }, "declares": { "type": "object", "description": "data-dr-declares: what the module does, stated for graders and app-space test \u2014 nothing draws from it and the runtime never reads it. Every key is optional; a name it lists must be one the contract declares (custom_declares)", "additionalProperties": false, "properties": { "reads": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the data.sources entries and handlers whose answers it draws" }, "calls": { "type": "array", "items": { "type": "string", "minLength": 1 }, "description": "the handlers it calls through ui.call; app-space test reports a call to any other (custom-undeclared-call)" }, "produces": { "type": "object", "description": `per called handler, the payload keys it sends \u2014 {"project": ["growth", "hires"]}; for a handler it does not list, app-space test reads the keys off the module's ui.call object literal`, "additionalProperties": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "shows": { "type": "array", "description": "the numbers it displays; the module projects each one on the element that shows it (data-dr-field, data-dr-value, data-dr-format), which app-space test harvests into the element's values", "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the field the number is, as its data-dr-field names it" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how it reads, as its data-dr-format says" }, "scale": { "enum": ["fraction"], "description": "fraction: the value is a share (0.04) shown as a percent (4%)" } } } } } } } }, "field": { "type": "object", "properties": { "entity": { "type": "string", "description": "data-dr-entity: the table the column is in" }, "field": { "type": "string", "description": "data-dr-field: the column" }, "source": { "type": "string", "description": "data-dr-source: the handler that answers its choices" }, "label": { "type": "string", "description": "the field's label" }, "required": { "type": "boolean", "description": "true when the form cannot be saved without it" }, "input_type": { "type": "string", "description": "the input's type" }, "options": { "type": "array", "description": "the choices offered" } } }, "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent", "text", "date"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads; default text" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how actual, plan and variance read; default currency" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how actual, plan and variance read below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } }, "slider": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this slider writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this slider reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "min": { "type": "number", "description": "the track's low end, in stored units; default the page param's min (param mode), else 0" }, "max": { "type": "number", "description": "the track's high end, in stored units; default the page param's max (param mode). Required one way or the other: a slider with neither draws its 'slider needs a max' panel (1.0.1) and the compiler refuses it (part_bounds)" }, "step": { "type": "number", "description": "the increment the value moves by, in stored units; every value set is a multiple of it from min; default the page param's step, else 1" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value beside the track reads; default number" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "show_value": { "type": "boolean", "description": "whether the formatted value is drawn beside the track; default true" }, "marks": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value"], "properties": { "value": { "type": "number", "description": "where the mark sits, in stored units" }, "label": { "type": "string", "description": "what the mark says; default the value, formatted" } } }, "description": "labelled ticks under the track" }, "value": { "type": "number", "description": "field mode: the value it starts on; default min. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the slider's label; default the page param's label (param mode), else the element's label" } }, "description": "data-dr-props: the slider part's typed props, handed to it as PartProps.props" } } } });
17684
17894
  var LIBRARY_TYPES2 = Object.freeze(["number_input", "tabs", "tab_panel", "select", "date_picker", "data_grid", "dialog", "variance_table", "toggle", "control_group", "callout", "scenario_columns"]);
17685
- var LIBRARY_PROPS_SCHEMAS2 = Object.freeze({ "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "enum": ["currency", "number", "percent"], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent", "text", "date"], "description": "how the value reads; default text" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "enum": ["currency", "number", "percent"], "description": "how actual, plan and variance read; default currency" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "enum": ["currency", "number", "percent"], "description": "how the value reads" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } } });
17895
+ var LIBRARY_PROPS_SCHEMAS2 = Object.freeze({ "number_input": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["format"], "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this input writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this input reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "what the number is: the unit shown beside the input" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "min": { "type": "number", "description": "the lowest number a reader may type, in the units they type it in; param mode: default the page param's min" }, "max": { "type": "number", "description": "the highest number a reader may type, in the units they type it in; param mode: default the page param's max" }, "step": { "type": "number", "description": "the increment the arrow keys move by, in the units typed; default 1 (param mode: the page param's step). In param mode a typed value is rounded to it before it is set" }, "decimals": { "type": "integer", "minimum": 0, "description": "the decimals the STORED value is rounded to, after scaling; default as typed" }, "value": { "type": "number", "description": "field mode: the stored value the input starts from (0.04, not 4, under fraction); default empty. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the input's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "the hint shown while the input is empty" } }, "description": "data-dr-props: the number_input part's typed props, handed to it as PartProps.props" } } }, "tabs": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tabs"], "properties": { "tabs": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["id", "label"], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the tab's id, which a tab_panel's tab names" }, "label": { "type": "string", "minLength": 1, "description": "the text on the tab" } } }, "description": "the tabs, in order" }, "default": { "type": "string", "description": "the id of the tab open first; default the first tab" } }, "description": "data-dr-props: the tabs part's typed props, handed to it as PartProps.props" } } }, "tab_panel": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "required": ["tab"], "properties": { "tab": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]*$", "description": "the id of the tab (in the enclosing tabs) this panel belongs to" } }, "description": "data-dr-props: the tab_panel part's typed props, handed to it as PartProps.props" } } }, "select": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: optional; the handler whose rows are the options when props.options is absent" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this select writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this select reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "options": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": ["value", "label"], "properties": { "value": { "type": "string", "minLength": 1, "description": "what is stored" }, "label": { "type": "string", "description": "what the reader sees" } } }, "description": "the options; when absent they are the page param's values (param mode), else the source rows" }, "option_value": { "type": "string", "description": "with a source: the row column that is stored; default id" }, "option_label": { "type": "string", "description": "with a source: the row column the reader sees; default the value column" }, "value": { "type": "string", "description": "field mode: the option chosen first; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a choice; default Choose\u2026" } }, "description": "data-dr-props: the select part's typed props, handed to it as PartProps.props" } } }, "date_picker": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this picker writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this picker reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "mode": { "enum": ["date", "month"], "description": "date (the default) stores YYYY-MM-DD; month stores YYYY-MM. Param mode over a month param is month" }, "value": { "type": "string", "pattern": "^[0-9]{4}-[0-9]{2}(-[0-9]{2})?$", "description": "field mode: the date or month the picker starts on; default none. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the control's label; default the page param's label (param mode), else the element's label" }, "placeholder": { "type": "string", "description": "what the control says before a pick; default Pick a date / Pick a month" } }, "description": "data-dr-props: the date_picker part's typed props, handed to it as PartProps.props" } } }, "data_grid": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows the grid shows" }, "props": { "type": "object", "additionalProperties": false, "required": ["columns"], "properties": { "columns": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row key the column shows" }, "label": { "type": "string", "description": "the header; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent", "text", "date"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads; default text" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "align": { "enum": ["start", "end"], "description": "default end for currency, number and percent, start otherwise" }, "sortable": { "type": "boolean", "description": "whether the header sorts; default true" } } }, "description": "the columns, in order" }, "key": { "type": "string", "description": "the column whose value is each row's data-dr-row, and the id a row action posts; default id. A row without it projects its position as data-dr-row and draws no row actions (1.1.1); with row_actions the compiler requires it stated and a column the source's rows carry, and, where a row action writes through a remove, save or decide handler, that table's primary key (part_row_key)" }, "page_size": { "type": "integer", "minimum": 5, "description": "rows per page; default 10" }, "sort": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the column sorted first" }, "dir": { "enum": ["asc", "desc"], "description": "default asc" } }, "description": "the order the rows start in; default the order the handler answered" }, "on_row": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {row} when a reader opens a row; the page re-reads after it" }, "row_actions": { "type": "array", "minItems": 1, "items": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["label", "dialog"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "dialog": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_-]*$", "description": "the id of a dialog on this page whose values_from is row: it opens over the row, its inputs prefilled, and posts id with its fields" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }, { "type": "object", "additionalProperties": false, "required": ["label", "call"], "properties": { "label": { "type": "string", "minLength": 1, "description": "the text on the row's button" }, "call": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "a handler called with {id, row} (id: the row's key column); the page re-reads after it" }, "confirm": { "type": "string", "minLength": 1, "description": "the question asked before the call runs (Confirm / Cancel); default none" }, "role": { "type": "string", "minLength": 1, "description": "the one app role that sees this action; absent means every role (the handler's own requiresRole is the control)" } } }] }, "description": "a button per row for each action, after the columns: open a dialog over the row, or call a handler with it" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the data_grid part's typed props, handed to it as PartProps.props" } } }, "dialog": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "trigger": { "type": "string", "minLength": 1, "description": "the text on the button that opens it; default the element's label, else its title \u2014 the compiler writes it into the page (foldDialogTriggers). A dialog with none of the three and no values_from row is refused (part_mode); a row dialog (values_from row) takes none, a row action opens it" }, "title": { "type": "string", "description": "the dialog's title; default the element's label" }, "description": { "type": "string", "description": "one line under the title" }, "confirm": { "type": "string", "description": "the text on the confirm button; default Confirm" }, "on_confirm": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*$", "description": "the handler Confirm calls with the fields of the inputs inside; without one, Confirm only closes" }, "values_from": { "enum": ["row"], "description": "row: a data_grid row action opens it over one row \u2014 the inputs inside start from that row's values, and Confirm posts id (the row's key) with their fields, to a save handler" }, "key": { "type": "string", "minLength": 1, "description": "with values_from row: the row column posted as id; default the grid's key, else id" } }, "description": "data-dr-props: the dialog part's typed props, handed to it as PartProps.props" } } }, "variance_table": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler whose rows are the lines" }, "props": { "type": "object", "additionalProperties": false, "required": ["row", "actual", "plan"], "properties": { "row": { "type": "string", "minLength": 1, "description": "the column naming each line; its value is the line's data-dr-row" }, "actual": { "type": "string", "minLength": 1, "description": "the column holding the actual figure" }, "plan": { "type": "string", "minLength": 1, "description": "the column holding the plan (budget) figure" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how actual, plan and variance read; default currency" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how actual, plan and variance read below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good: higher (the default) for revenue, lower for cost" }, "threshold": { "type": "object", "additionalProperties": false, "required": [], "properties": { "abs": { "type": "number", "minimum": 0, "description": "a variance smaller than this, in the figures' units, is neutral" }, "pct": { "type": "number", "minimum": 0, "description": "a variance share smaller than this fraction (0.05 is 5%) is neutral" } }, "description": "below both limits a variance is neutral rather than toned; default none" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the variance_table part's typed props, handed to it as PartProps.props" } } }, "toggle": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "field": { "type": "string", "pattern": "^[a-z][a-z0-9_]*$", "description": "field mode: the payload key this switch writes \u2014 a hidden input of that name carries the raw value, and the form or dialog it sits in posts it; exactly one of field and param" }, "param": { "type": "string", "minLength": 1, "description": "param mode: the page param (pages[].params[].name) this switch reads from ctx.params and moves with ctx.setParam \u2014 it writes no hidden input, and the page's readers re-read when it moves; exactly one of field and param" }, "value": { "type": "boolean", "description": "field mode: whether it starts on; default off. Param mode reads ctx.params instead" }, "label": { "type": "string", "description": "the switch's label; default the page param's label (param mode), else the element's label" }, "description": { "type": "string", "description": "one line under the label" } }, "description": "data-dr-props: the toggle part's typed props, handed to it as PartProps.props" } } }, "control_group": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "props": { "type": "object", "additionalProperties": false, "properties": { "columns": { "enum": [1, 2, 3, 4], "description": "how many controls sit side by side; default 1 (under 640px always 1)" }, "label_position": { "enum": ["top", "start"], "description": "top (the default): each label above its control; start: every label in one column before its control" }, "description": { "type": "string", "description": "one line above the controls" } }, "description": "data-dr-props: the control_group part's typed props, handed to it as PartProps.props" } } }, "callout": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose answer the rules read \u2014 a summary's measures, a KPI, or rows" }, "props": { "type": "object", "additionalProperties": false, "required": ["rules"], "properties": { "rules": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["when", "tone", "text"], "properties": { "when": { "oneOf": [{ "type": "object", "additionalProperties": false, "required": ["path", "gte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "gte": { "type": "number", "description": "matches when the value is at least this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "lte"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "lte": { "type": "number", "description": "matches when the value is at most this" } } }, { "type": "object", "additionalProperties": false, "required": ["path", "eq"], "properties": { "path": { "type": "string", "pattern": "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z0-9_]+)*$", "description": "a dotted path into the source's answer: current_arr, kpi.value, rows.0.arr" }, "eq": { "type": ["string", "number", "boolean"], "description": "matches when the value is exactly this" } } }], "description": "the condition: one path and one of gte, lte, eq" }, "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } } }, "description": "tried in order; the first whose when holds is the sentence" }, "default": { "type": "object", "additionalProperties": false, "required": ["tone", "text"], "properties": { "tone": { "enum": ["positive", "neutral", "warning", "negative"], "description": "the callout's tone" }, "text": { "type": "string", "minLength": 1, "description": "the sentence, a template: {path} is the value as text, {path|currency}, {path|number} and {path|percent} a graded number (data-dr-field, data-dr-value, data-dr-format)" } }, "description": "what it says when no rule holds; default nothing" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" } }, "description": "data-dr-props: the callout part's typed props, handed to it as PartProps.props" } } }, "scenario_columns": { "type": "object", "additionalProperties": false, "required": ["props"], "properties": { "id": { "type": "string", "description": "data-dr-id: the element's stable id, unique on its page" }, "label": { "type": "string", "description": "data-dr-label: the title a reader sees" }, "role": { "type": "string", "description": "data-dr-role: the app role this element is meant for; absent means every role" }, "span": { "type": "integer", "description": "data-dr-span: columns of the kit's twelve" }, "section": { "type": "string", "description": "the page section the element sits in (the nearest data-dr-section)" }, "source": { "type": "string", "description": "data-dr-source: the handler (or data.sources entry) whose rows are the scenarios" }, "props": { "type": "object", "additionalProperties": false, "required": ["key", "label_field", "metrics"], "properties": { "key": { "type": "string", "minLength": 1, "description": "the column naming each row uniquely; its value is the column's data-dr-row" }, "label_field": { "type": "string", "minLength": 1, "description": "the column whose value heads each scenario's column" }, "metrics": { "type": "array", "minItems": 1, "items": { "type": "object", "additionalProperties": false, "required": ["field"], "properties": { "field": { "type": "string", "minLength": 1, "description": "the row column the line shows" }, "label": { "type": "string", "description": "the line's name; default the field, humanised" }, "format": { "anyOf": [{ "enum": ["currency", "number", "percent"] }, { "type": "string", "maxLength": 64, "pattern": "^(General|[^\\u0000-\\u001f]*[#0][^\\u0000-\\u001f]*)$", "description": "a platform values_format string, as a Datarails dashboard writes it: #,### $#,###.## #,###.#[kilo]k #,###;[Red](#,###); drawn by dr-fmt 2" }], "description": "how the value reads" }, "negative": { "enum": ["minus", "red_minus", "absolute", "red_absolute"], "description": "how the value reads below zero: the platform's negative-number mode (NegativeNumbersFormat), applied below zero only: minus -1,234 | red_minus in red | absolute (1,234) | red_absolute (1,234) in red; default minus" }, "scale": { "enum": ["units", "fraction"], "description": "percent only: units (the default) means 4 is 4%; fraction means 0.04 is 4%" }, "currency": { "type": "string", "pattern": "^[A-Z]{3}$", "description": "currency only: the ISO code; default USD" }, "favorable": { "enum": ["higher", "lower"], "description": "which way is good for the delta's tone: higher (the default) or lower" } } }, "description": "the lines, in order" }, "max": { "type": "integer", "minimum": 1, "description": "how many rows may be ticked at once; default 3 (at most 6)" }, "baseline": { "type": "string", "minLength": 1, "description": "the key value of the row every delta is against; default the first row" }, "empty_text": { "type": "string", "description": "what the empty state says; default the registry's sentence, Nothing to show." } }, "description": "data-dr-props: the scenario_columns part's typed props, handed to it as PartProps.props" } } } });
17686
17896
  var CONTROLS_TYPES2 = Object.freeze(["slider"]);
17687
17897
  var PARTS2 = Object.freeze({ "number_input": { "module": "dr-components", "reads": null, "children": "none", "events": {}, "empty": null }, "tabs": { "module": "dr-components", "reads": null, "children": ["tab_panel"], "events": {}, "empty": null }, "tab_panel": { "module": "dr-components", "reads": null, "children": "any", "events": {}, "empty": null }, "select": { "module": "dr-components", "reads": { "roles": ["list", "custom"], "as": "rows" }, "children": "none", "events": {}, "empty": null }, "date_picker": { "module": "dr-components", "reads": null, "children": "none", "events": {}, "empty": null }, "data_grid": { "module": "dr-components", "reads": { "roles": ["list", "inbox", "custom"], "as": "rows" }, "children": "none", "events": { "on_row": ["custom", "decide"], "on_row_action": ["remove", "decide", "custom", "submit", "save"] }, "empty": "Nothing to show." }, "dialog": { "module": "dr-components", "reads": null, "children": "any", "events": { "on_confirm": ["custom", "save", "submit", "decide"] }, "empty": null }, "variance_table": { "module": "dr-components", "reads": { "roles": ["list", "custom"], "as": "rows" }, "children": "none", "events": {}, "empty": "Nothing to show." }, "toggle": { "module": "dr-components", "reads": null, "children": "none", "events": {}, "empty": null }, "control_group": { "module": "dr-components", "reads": null, "children": ["number_input", "select", "date_picker", "toggle", "slider"], "events": {}, "empty": null }, "callout": { "module": "dr-components", "reads": { "roles": ["summary", "list", "custom"], "as": "payload" }, "children": "none", "events": {}, "empty": null }, "scenario_columns": { "module": "dr-components", "reads": { "roles": ["list", "custom"], "as": "rows" }, "children": "none", "events": {}, "empty": "Nothing to show." }, "slider": { "module": "dr-components-controls", "reads": null, "children": "none", "events": {}, "empty": null } });
17688
17898
  var TITLED_TYPES2 = Object.freeze(["widget", "form", "list", "queue", "stat", "chart", "custom", "number_input", "select", "date_picker", "dialog"]);
@@ -17705,6 +17915,7 @@ var COMPONENT_TYPE_SET2 = new Set(COMPONENT_TYPES5);
17705
17915
  var MODULE_RE2 = /^components\/[a-z][a-z0-9_-]*\.js$/;
17706
17916
  var CHART_KINDS6 = CHART_KINDS5;
17707
17917
  var WIDGET_KINDS5 = WIDGET_KINDS4;
17918
+ var PLATFORM_FORMAT_RE2 = new RegExp(PLATFORM_FORMAT2.pattern, "u");
17708
17919
  var COMPONENT_PROPS5 = COMPONENT_PROPS4;
17709
17920
  function parseFilter2(raw) {
17710
17921
  const filter = {};
@@ -20917,6 +21128,56 @@ function layoutProblems(contract, { moduleSource = () => void 0 } = {}) {
20917
21128
  return out;
20918
21129
  }
20919
21130
 
21131
+ // ../flows/appspace-builder/kit/contract/platformPalette.mjs
21132
+ var PLATFORM_CHART2 = Object.freeze([
21133
+ "#008aff",
21134
+ "#91e7e7",
21135
+ "#f37789",
21136
+ "#ffdc65",
21137
+ "#0e569d",
21138
+ "#bbe0ff",
21139
+ "#57b2ff",
21140
+ "#5ecfb9",
21141
+ "#c7ffda",
21142
+ "#179ab9"
21143
+ ]);
21144
+ var APP_CHART_ORDER2 = Object.freeze([
21145
+ "#008aff",
21146
+ // 3.45:1, the platform's first colour, still series 1 (Actuals)
21147
+ "#0e569d",
21148
+ // 7.40:1, Forecast (`--dr-series-forecast`)
21149
+ "#179ab9",
21150
+ // 3.30:1
21151
+ "#f37789",
21152
+ // 2.69:1
21153
+ "#57b2ff",
21154
+ // 2.28:1
21155
+ "#91e7e7",
21156
+ // 1.42:1
21157
+ "#bbe0ff",
21158
+ // 1.38:1
21159
+ "#5ecfb9",
21160
+ // 1.89:1, held at 8: the variance colour (`colors[7]`)
21161
+ "#ffdc65",
21162
+ // 1.34:1
21163
+ "#c7ffda"
21164
+ // 1.12:1
21165
+ ]);
21166
+ var APP_FORECAST2 = "var(--dr-chart-2)";
21167
+ var PALETTE_FILE2 = "ui/dr-palette.css";
21168
+ function paletteTokens2() {
21169
+ const tokens = {};
21170
+ APP_CHART_ORDER2.forEach((colour, i) => {
21171
+ tokens[`--dr-chart-${i + 1}`] = colour;
21172
+ });
21173
+ tokens["--dr-series-forecast"] = APP_FORECAST2;
21174
+ return tokens;
21175
+ }
21176
+ function isPlatformChartColour2(n, value) {
21177
+ const colour = String(value ?? "").trim().toLowerCase();
21178
+ return colour !== "" && (PLATFORM_CHART2[n - 1] === colour || APP_CHART_ORDER2[n - 1] === colour);
21179
+ }
21180
+
20920
21181
  // ../flows/appspace-builder/kit/checks/rules/theme.mjs
20921
21182
  var THEME_FILE7 = "ui/theme.css";
20922
21183
  var THEME_ATTR4 = "data-dr-theme";
@@ -20939,11 +21200,14 @@ var CONTRAST_RULES2 = [
20939
21200
  ["--dr-chart-6", 3, "chart series 6"],
20940
21201
  ["--dr-chart-7", 3, "chart series 7"],
20941
21202
  ["--dr-chart-8", 3, "chart series 8"],
21203
+ // ui-kit/v4 draws ten series (the platform's ten).
21204
+ ["--dr-chart-9", 3, "chart series 9"],
21205
+ ["--dr-chart-10", 3, "chart series 10"],
20942
21206
  ["--dr-border", 1.3, "the card border"]
20943
21207
  ];
20944
21208
  var FLOORS2 = new Map(CONTRAST_RULES2.map(([token, floor, what]) => [token, { floor, what }]));
20945
21209
  function checkTheme2(app) {
20946
- const violations = [];
21210
+ const violations = [...paletteFileViolations2(app)];
20947
21211
  const file = app.ui.find((entry) => entry.path === THEME_FILE7);
20948
21212
  if (!file) return { violations };
20949
21213
  const overrides = rootTokens2(file.text);
@@ -20964,6 +21228,8 @@ function checkTheme2(app) {
20964
21228
  if (!rule) continue;
20965
21229
  const value = resolve11(token, overrides);
20966
21230
  if (value === null) continue;
21231
+ const series = /^--dr-chart-(\d+)$/.exec(token);
21232
+ if (series && isPlatformChartColour2(Number(series[1]), value)) continue;
20967
21233
  const ratio = contrast2(rgbOf3(value, ground), ground);
20968
21234
  if (ratio === null) {
20969
21235
  violations.push({
@@ -20984,6 +21250,20 @@ function checkTheme2(app) {
20984
21250
  }
20985
21251
  return { violations: dedupe3(violations) };
20986
21252
  }
21253
+ function paletteFileViolations2(app) {
21254
+ const file = app.ui.find((entry) => entry.path === PALETTE_FILE2);
21255
+ if (!file) return [];
21256
+ const stated2 = rootTokens2(file.text);
21257
+ const expected = paletteTokens2();
21258
+ const out = [];
21259
+ const say = (line, message) => out.push({ rule: "R2.8", where: `${PALETTE_FILE2}:${line}`, message });
21260
+ for (const [token, { value, line }] of stated2) {
21261
+ if (!(token in expected)) say(line, `${PALETTE_FILE2} declares ${token}, which the compiler never writes there; the file is generated \u2014 put an app's own colours in app.theme (ui/theme.css)`);
21262
+ else if (value.toLowerCase() !== expected[token]) say(line, `${PALETTE_FILE2} sets ${token} to ${value}, and the compiler writes ${expected[token]}; the file is generated \u2014 put an app's own colours in app.theme (ui/theme.css), where R2.8 measures them`);
21263
+ }
21264
+ for (const token of Object.keys(expected)) if (!stated2.has(token)) say(1, `${PALETTE_FILE2} is missing ${token}; the file is generated \u2014 recompile rather than edit it`);
21265
+ return out;
21266
+ }
20987
21267
  function themesInUse2(app) {
20988
21268
  const found = /* @__PURE__ */ new Set();
20989
21269
  for (const page of app.pages) {
@@ -22037,7 +22317,6 @@ var kit_default2 = {
22037
22317
  checks: "checks/run.mjs",
22038
22318
  contract: "contract/extract.mjs",
22039
22319
  charts: "echarts@5.6.0",
22040
- fmt: "dr-fmt@1.0.0",
22041
22320
  appWidgets: "dr-app-widgets@1.1.0",
22042
22321
  appComponents: "dr-components@1.1.1",
22043
22322
  appControls: "dr-components-controls@1.0.1"