mcpField
H
hub-editor

hub-editor

github.com/datexDesign & UI98 installs
Repository

About hub-editor

A skill for modifying existing Datex Studio hubs by editing their configuration. It covers toolbar buttons and their click flows, with a fetch-edit-upsert workflow and verification steps.

Key features

  1. 01Edit hub toolbar buttons
  2. 02Configure button click flows
  3. 03Keep toolbar[] and flows[] aligned
  4. 04Update configurations with dxs configuration
  5. 05Validate JSON and changes

Use cases

  1. 01Add a button that opens a report
  2. 02Rename or reorder toolbar buttons
  3. 03Remove a button and its flow reference

Install

Copy the command and run it in a terminal.

$npx skills add https://github.com/datex/skills --skill hub-editor

After installing, type/hub-editorin Claude Code to confirm it loaded.

Bundled filesreferences/hub-config-api.mdreferences/toolbar-and-click-flows.md

Details

From the project README

Hub Editor

Modify a Datex Studio hub configuration to add toolbar buttons, wire click flows, and integrate reports or other actions into a hub UI.

See also: hub-creator — authoring a NEW hub from scratch (this skill is for modifying existing hubs).

References

Dependencies

  • requirements-gathering skill — invoked to produce a requirements brief if one doesn't already exist
  • function-creator skill — invoked when the click flow does not yet exist as a Datex Studio function

CLI Status

Hub edits go through dxs configuration — the generic CRUD primitive over every platform configuration type (hub, grid, form, flow, footprintquerymanager, appconfig, etc.; run dxs configuration types to list all). The round-trip is the canonical pattern in ../datex-studio-shared/configuration-roundtrip.md. get -O writes the full server envelope; you MUST extract the inner .json body before upsert, or the push silently wipes the config (this bug was first caught on a hub):

dxs configuration get hub <configId> -b <branchId> -O envelope.json   # fetch (full envelope)
jq .json envelope.json > body.json                                    # extract inner body — REQUIRED
# edit body.json locally (toolbar[], flows[], …)
dxs configuration upsert hub -b <branchId> -D body.json               # push inner body

The branch is the source of truth; envelope.json / body.json are throwaway scratch files. There is no dxs hub subcommand and no field-level patching — you fetch the whole document, edit JSON, and push the whole document back. See ../datex-studio-shared/configuration-roundtrip.md for the canonical round-trip and references/hub-config-api.md for hub-specific details.

Note on naming: dxs configuration operates on platform configurations (hubs, grids, etc.) on a branch. dxs config (also aliased as dxs settings) operates on local CLI settings stored in ~/.datex/config.yaml. Prefer dxs settings in any context that also discusses dxs configuration — it eliminates the easy confusion.

Workflow

[Phase 1: Setup]
Follow branch-setup.md for branch selection
        |
[requirements brief in context?]
  +-----+-----+
  |            |
 YES          NO → invoke requirements-gathering
  |            |
  +-----+------+
        |
[Phase 2: Locate the hub]
Identify hub by reference name (e.g., inventory_hub)
        |
dxs source explore config <hub_ref> --branch <id>
  → extract: hub config ID
        |
[Phase 3: Fetch current hub configuration]
dxs configuration get hub <configId> -b <branchId> -O envelope.json
jq .json envelope.json > body.json          ← extract inner body (REQUIRED)
cp body.json body.json.orig                 ← save for diff
        |
[Phase 4: Plan the change]
What's changing?
  +------+------+------+
  |      |      |      |
 ADD   MODIFY REMOVE  RENAME
  toolbar       button       click flow
        |
[Phase 5: Click-flow prerequisite (if adding/changing a button)]
Does the target click flow function exist?
  +-----+-----+
  |           |
 YES         NO
  |           |
 use it    invoke function-creator
  |        (writes the .ts code,
  |         upserts the function,
  |         returns reference name)
  +-----+-----+
        |
[Phase 6: Edit body.json]
Modify toolbar[] and flows[] arrays per references/toolbar-and-click-flows.md
        |
[Phase 7: Validate locally]
python -m json.tool body.json > /dev/null   ← syntactic check
diff -u body.json.orig body.json            ← review the change
        |
[Phase 8: Push updated config]
dxs configuration upsert hub -b <branchId> -D body.json
        |
[Phase 9: Verify]
Reload the hub in the running app (or re-fetch and diff)
to confirm the change took effect

Phase Details

Phase 1: Setup

Follow ../datex-studio-shared/branch-setup.md. The branch ID is required by every dxs configuration command (-b/--branch) — pass it explicitly in skill examples; don't rely on implicit scoping.

Phase 2: Locate the hub

You need the hub configuration ID (configId). The simplest path:

dxs source explore config <hub_reference_name> --branch <branch_id>

This returns the hub config metadata, including its id. If you don't know the reference name, list configs filtered to the hub type:

dxs source explore configs --branch <branch_id> | grep -i hub

Hub configs use a configurationTypeId distinct from datasources (6) and functions (9). Check the dxs source explore configs output to see the type IDs in use on your branch.

Phase 3: Fetch current hub configuration
dxs configuration get hub <configId> -b <branch_id> -O envelope.json
jq .json envelope.json > body.json    # extract the inner body — see configuration-roundtrip.md
cp body.json body.json.orig           # diff target for Phase 7

get -O writes the full server envelope; upsert -D expects only the inner .json body. Skipping the extraction step pushes the envelope back and silently wipes the config — see ../datex-studio-shared/configuration-roundtrip.md. Always start from a fresh fetch — never edit a stale copy. See references/hub-config-api.md for hub-specific details.

Phase 4: Plan the change

The hub configuration has two interconnected arrays:

ArrayPurpose
toolbar[]UI buttons that appear in the hub's toolbar — each has a clickFlowConfig
flows[]Datex Studio flow function references the hub knows about — every flow referenced from a clickFlowConfig must appear here

A typical "add a toolbar button that launches a report" change touches both arrays: a new entry in toolbar[] and the click flow reference added to flows[]. See references/toolbar-and-click-flows.md for the JSON structure and the common patterns.

Phase 5: Click-flow prerequisite

Hub toolbar buttons execute a Datex Studio function as their click handler. If the target click flow function doesn't exist yet, invoke function-creator first. The click flow code typically:

  1. Reads the hub's date-range / context inputs from $flow.inParams
  2. Applies defaults for any missing values — see ../datex-studio-shared/flow-code-patterns.md for the canonical date-defaulting pattern using $utils.isDefined()
  3. Calls $shell.Reports.open{ref}() (or another shell action) with the resolved parameters

Reference ../datex-studio-shared/flow-code-patterns.md when authoring the click flow so the function-creator's output uses $utils.isDefined() (not != null) and the documented date-defaulting block.

Phase 6: Edit body.json

Use a JSON editor or jq to add/modify entries. Two safety rules:

  • Preserve everything you didn't change. Hub configs contain UI state, version stamps, and properties unrelated to your edit. dxs configuration upsert replaces the entire object; missing fields are deleted.
  • Keep toolbar[] and flows[] consistent. Every clickFlowConfig.reference in toolbar[] must have a matching entry in flows[], and vice versa.
Phase 7: Validate locally
python -m json.tool body.json > /dev/null      # JSON-parses?
diff -u body.json.orig body.json                # review actual changes

body.json.orig was saved in Phase 3 right after extraction — the diff is your only structural review before pushing.

Phase 8: Push updated config
dxs configuration upsert hub -b <branch_id> -D body.json

Push the extracted inner body (body.json), never the raw envelope.json. The -D/--data-file flag reads the body from a file, bypassing shell escaping entirely — so \r\n sequences and embedded quotes in the JSON are no longer a concern.

Phase 9: Verify

Re-fetch the config and compare inner bodies:

dxs configuration get hub <configId> -b <branch_id> -O envelope-after.json
jq .json envelope-after.json > body-after.json
diff -u body.json body-after.json

The diff should be empty (or contain only server-side fields like updatedDateTime). Reload the hub in the running app to confirm the new toolbar button appears and the click flow fires correctly.

Common Operations

OperationWhat changes
Add a toolbar button that opens a reporttoolbar[] gets a new entry; flows[] gets the click-flow reference; click flow function may need to be created
Change which report a button opensClick flow function code ($shell.Reports.open{newRef}(...)) — no hub-config change required if the flow reference stays the same
Rename / re-label a buttontoolbar[].label (or equivalent display field) — no flow change
Remove a buttonRemove the entry from toolbar[] AND the (now-orphaned) reference from flows[]
Reorder buttonsReorder toolbar[] entries

Key Rules

  • Extract the inner .json body before upsert. get -O writes the full envelope; jq .json envelope.json > body.json. Pushing the raw envelope silently wipes the config — see ../datex-studio-shared/configuration-roundtrip.md.
  • Never edit a stale body.json. Always re-fetch with dxs configuration get hub before edits — other users or releases may have modified the hub.
  • dxs configuration upsert replaces the entire config. Don't omit fields you didn't intend to change.
  • toolbar[] and flows[] must stay in sync. A toolbar button without a corresponding flow entry won't fire; an orphaned flow entry is harmless but should be cleaned up.
  • Click flow code must use $utils.isDefined() — see ../datex-studio-shared/flow-code-patterns.md. Native null checks misfire against Datex Studio's value model.
  • $shell.Reports.open{ref}() parameter keys are case-sensitive and must match the report's ReportParameters[].Name exactly.
  • Save body.json.orig after extraction. It's your only diff target before push.

Common Mistakes

MistakeFix
Pushing the raw envelope.json from get -O straight to upsert -DSilently wipes the hub (toolbar/flows/onInitFlowConfig reset to null). Extract first: jq .json envelope.json > body.json, then upsert -D body.json. See configuration-roundtrip.md
Trying dxs hub get / dxs hub updateThese commands don't exist. Use dxs configuration get hub / dxs configuration upsert hub
Using dxs config get <id> to fetch the hubdxs config (alias dxs settings) operates on local CLI settings, not platform configurations. Use dxs configuration get hub <id> -b <branchId>
Reading endpoints.py to construct a URL by handdxs configuration covers every type in KNOWN_TYPES — you no longer need the URL pattern. Reserve dxs api for endpoints not covered by dxs configuration
Trying dxs api --saveThat flag has never existed. Use -O/--output-file (writes raw JSON) on dxs api, or use dxs configuration get ... -O
Falling back to a Python httpx.put() helper for large bodiesNo longer needed. dxs configuration upsert -D <file> and dxs api PUT -D <file> both read the body from a file and bypass shell escaping
Piping `dxs api GET ...tail -n +2` to strip a preamble
Forgetting -b/--branch on dxs configuration commandsThe flag is required. Pass it explicitly in every example
Adding a toolbar[] button without adding to flows[]Button renders but doesn't fire. Both arrays must reference the click flow
Using != null or !startDate in click flow codeUse $utils.isDefined(startDate) — Datex Studio's value model doesn't compare cleanly with literal null/undefined
Mismatched parameter keys in $shell.Reports.open{ref}()Keys are case-sensitive and must match the report's parameter Name values exactly. Mismatches silently render with the parameter unset
Pushing an edited config that's missing fields from the originalupsert replaces the whole object; omitted fields get deleted. Always start from a fresh get and only modify what you mean to change

After your edit, invoke post-edit-verification to surface description/JSON/schema violations. For a final review, invoke component-validator.

Comments

Markdown supported