Custom Diagram Creator

Data model

The JSON format of a diagram and how it is stored in Grail.

Diagram

A diagram is a JSON document validated by the zod schema in ui/app/model/schema.ts. A JSON Schema export lives in skill/diagram.schema.json (npm run export:schema regenerates it).

FieldTypeNotes
schemaVersion"1.0"
idstringUUID v4
name, description, ownerstringdescription and owner are optional
createdAt, updatedAtstringISO 8601 UTC
settings.backgrounddots | grid | blankdefault dots
settings.defaultTimeframe{ from, to }expressions such as now()-2h or ISO 8601
settings.refreshIntervaloff | 30s | 1m | 5m | 15m | 30mdefault off
settings.viewport{ x, y, zoom }optional; saved with the diagram
nodes, edgesarrayssee below

Node

FieldTypeNotes
idstringunique in the diagram
typeentityNode | customNodemust match data.kind
position{ x, y }
size{ w, h }optional; set when the node is resized
dataentity | customdiscriminated by kind

Entity component

FieldTypeNotes
componentTypestringone of: frontend, mobile, service, process, genai, host, container, database, networkDevice, k8sCluster, k8sNamespace, k8sNode, workload, k8sPod, k8sService, k8sIngress, awsEc2, awsLambda, awsEcs, awsEks, awsRds, awsDynamoDb, awsElastiCache, awsS3, awsSqs, awsSns, awsLoadBalancer, awsApiGateway, azureVm, azureAppService, azureFunction, azureContainerApp, azureAks, azureSql, azureCosmosDb, azureRedis, azureStorage, azureServiceBus, azureEventHubs, azureLoadBalancer, azureAppGateway, azureApim, gcpVm, gcpCloudRun, gcpPubSub
name, iconstringicon = export name from @dynatrace/strato-icons
entities{ id, name, classicId?, endpoint? }[]entities picked in the editor; default []. Endpoint picks keep the service id in id and the endpoint in endpoint
entityDqlstringoptional; used only when nothing is picked. Returns id (and preferably name)
failPoint.problemMatchstringoptional DQL filter fragment
failPoint.warningMin, failingMininteger ≥ 1problems open in the timeframe to turn orange / red
kpiKPI blockoptional, see below

Custom component

FieldTypeNotes
modeentities | slos
entities.dqlstringreturns id and name
entities.subNameFieldstringcolumn used as child name (default name)
entities.criterionanyProblem | matchmatch uses problemMatch
slos{ id, name }[]SLOs mode
maxVisibleRowsinteger ≥ 1default 8
kpiKPI blockoptional, see below

KPI block

FieldTypeNotes
enabled, titleboolean, stringshow the block and its heading
items[].idstringunique within the block
items[].dqlstringreturns a numeric column
items[].valueFieldstringoptional; default: first numeric column
items[].labelModetext | columnfixed name (first row) or one line per row
items[].labelText, labelFieldstringthe fixed name, or the name column (default: first text column)
items[].unit, decimals, maxRowsstring, 0–10, 1–50unit text, decimals, lines in column mode
items[].titlestringoptional: name shown above the KPI's lines when they are named from a column
items[].presetstringoptional: key of the ready-made KPI it came from (ui/app/model/kpiPresets.ts); the query may use $entityIds and friends
dql, maxRowsstring, integerlegacy single-table block (≤ 0.2); read as one column KPI

Edge

FieldTypeNotes
source, targetstringnode ids
sourceHandle, targetHandlet | r | b | loptional node side
typenormal | kpi
directionforward | backward | nonedefault forward
labelstringoptional
kpi.dqlstringreturns a single value
kpi.valueField, unit, decimalsoptional column, unit text, 0–10 decimals
kpi.threshold{ direction, warning, failing }above: high is bad · below: low is bad
kpi.animatedbooleandefault true

Example

json
{
  "schemaVersion": "1.0",
  "id": "8f0d6a4e-2f1b-4c55-9e4a-1f2d3c4b5a69",
  "name": "Checkout",
  "createdAt": "2026-10-04T00:00:00Z",
  "updatedAt": "2026-10-04T00:00:00Z",
  "settings": { "background": "dots", "defaultTimeframe": { "from": "now()-2h", "to": "now()" }, "refreshInterval": "off" },
  "nodes": [
    {
      "id": "web", "type": "entityNode", "position": { "x": 0, "y": 0 },
      "data": {
        "kind": "entity", "componentType": "frontend", "name": "Web shop", "icon": "ApplicationsIcon",
        "entities": [{ "id": "FRONTEND-12DCB920668AFDF0", "name": "Web shop", "classicId": "APPLICATION-EA7C4B59F27D43EB" }],
        "failPoint": { "warningMin": 1, "failingMin": 2 },
        "kpi": {
          "enabled": true, "title": "KPIs",
          "items": [
            { "id": "k1", "dql": "fetch user.events\n| summarize events = count()", "valueField": "events",
              "labelMode": "text", "labelText": "User events", "unit": "count", "decimals": 0, "maxRows": 5 }
          ]
        }
      }
    },
    {
      "id": "api", "type": "entityNode", "position": { "x": 380, "y": 0 },
      "data": {
        "kind": "entity", "componentType": "service", "name": "Checkout API", "icon": "ServicesIcon",
        "entityDql": "smartscapeNodes \"SERVICE\"\n| filter contains(name, \"checkout\", caseSensitive: false)\n| fields id, name",
        "failPoint": { "problemMatch": "event.category == \"ERROR\"", "warningMin": 1, "failingMin": 1 }
      }
    }
  ],
  "edges": [
    {
      "id": "e1", "source": "web", "target": "api", "sourceHandle": "r", "targetHandle": "l",
      "type": "kpi", "direction": "forward", "label": "Response time",
      "kpi": {
        "dql": "timeseries r = avg(dt.service.request.response_time, scalar: true)\n| fieldsAdd v = r / 1000\n| fields v",
        "unit": "ms", "decimals": 1, "animated": true,
        "threshold": { "direction": "above", "warning": 300, "failing": 800 }
      }
    }
  ]
}

Lookup row

Each diagram is one JSONL row of /lookups/custom-diagram-creator/diagrams:

ColumnTypeNotes
idstringlookup key
name, description, ownerstringcopies used by the list
createdAt, updatedAtstringISO 8601; updatedAt drives the concurrency check
deletedbooleantrue only for the metadata row and the placeholder kept when the last diagram is deleted
payloadstringbase64 of the UTF-8 JSON of the whole diagram
dql
load "/lookups/custom-diagram-creator/diagrams"
| filter isFalseOrNull(deleted)
| fields id, name, description, owner, createdAt, updatedAt
| sort updatedAt desc