A VS Code custom editor that opens SyteLine IDS form JSON files (*.ids.json) in a visual designer instead of raw text.
Features
- Custom editor on
**/*.ids.json — opens forms visually, with an "Open as JSON" button to fall back to text.
- Form tab — edit form metadata (name, caption, template, primary IDO, datasource, initial command, filter form spec) and toggle
primary_standardoperations.
- Layout tab with three views — Tree, Preview, and Split:
- Container tree reassembled from the flat
layout.notebooks / sections / components arrays (containment is by container name reference). Grid columns nest under their grid; template panes (##…) and no-container items collapse into a single (root).
- Add / duplicate / delete on every node; a toolbar to add components (any of 35 types), groups/sections, and notebooks.
- Drag-drop to reparent (onto a container) or reorder (onto a sibling).
- Visual preview canvas rendering containers as boxes and components on a CSS grid by
position.row/column; add per box, delete per cell, and drag-drop in/out of containers.
- Properties panel for the selected component / section / notebook, including
component_class { name, parameters }, enabled_when / visible_when / required_when, and component events.
- Events tab — searchable, inline-editable table with add/delete. Responses grouped by event name; the array order within a group is the firing sequence. Move to event… opens a picker to send one response to another event (existing or brand-new) by name, which works regardless of the filter or scroll position, and the group header can duplicate the whole event — every response, in order, copied to a new
<name>Copy event. Drag-drop still reorders within a group. When a filter hides part of a group the count badge reads 1/3, since reordering is relative to the hidden rows too.
- Variables tab — searchable, inline-editable table with add/delete.
- Script tab — read-only view of the embedded
form_script, editable in a real VB/C# editor. In that
editor, Go to Event (F12 / Ctrl+Click) on a (ThisForm.)GenerateEvent("Foo") / PostEvent("Foo")
call jumps to the event's FormScriptMethod handler in the same script (or the event's definition in the
form JSON when it isn't a script method).
- Focus Order tab — inspect each collection's derived field focus sequence beside its grid column order, with a one-click reorder fix when they diverge.
- IDO Usage side panel — inspect the structured IDO footprint computed by the Form Designer extension-owned API in a compact collapsible tree, including bound collections, datasource variables, event method targets, loaded collections, list lookups with their source components, and subcollection paths; filter by text or usage type, and click an IDO, component, or event to navigate directly to it. Shared side-panel tabs have equal-width cells for stable navigation.
- Feature Gates side panel — every SyteLine feature the form depends on (both
.ids and .iv2), detected from any Is…ActiveVar reference (declarative #GV(...) expressions, component enabled_when/visible_when/required_when/validators/list_source, event responses, and the embedded form_script). Features are grouped by feature ID with their usage places as a second level: click a usage row to jump to the variable, component, event, or script, or click the feature ID to open its Jira issue (base URL from slIds.jiraBrowseBaseUrl). Use Expand all / Collapse all to open or close every visible feature at once, or click the feature ID to open its Jira issue (base URL from slIds.jiraBrowseBaseUrl) — only feature ids under a known Jira project prefix (CSIB) are linked; internal SyteLine codes (RS…, etc.) render as plain text. A Delivery Tracking toolbar action opens the Feature Delivery Tracking wiki for checking release status. Activation status is resolved automatically and headlessly through the MG REST Client extension's public API (an AppFeatures LoadCollection), and each feature reports a Type-aware status — Force GA, GA Active, GA Off, Pre-Release On/Off, Hidden On/Off — with its FeatureType / ActivatedBy / ActivationDate beside the ID. Active is the authoritative on/off flag; ActivatedBy (INFOR/sa = force) applies to GA (A) rows only, since H/P features are never GA. Every verdict is an inference from editable AppFeature_mst rows, so the panel shows a prominent advisory: for reference only, verify against the database and the running configuration. The connection is reused from the MG REST Client's active profile, and the credential is borrowed from that extension's own Get Security Token command, so nothing has to be configured twice (override via slIds.mgRest.*, or store a secret with IDS Form: Set MG REST Password/Token). If it cannot authenticate, gates read Unknown with the reason, an inline button to store a credential, and Open activation SQL — a T-SQL script opened in a SQL editor that reads AppFeature_mst (the AppFeature view is site-scoped by CONTEXT_INFO(), so it returns nothing outside the middle tier), scoped to one site so the result is one row per feature. The COUI tab carries a compact entry point; feature gates are not part of the readiness score.
- Component Flags editor — the Component Editor's
flags field keeps its numeric fallback and opens a grouped checkbox popup for the readable ComponentFlags options. Shared enum aliases use one checkbox per bit, the aggregate value is recalculated live, tooltips include the enum names and bit values, and unknown flags are preserved.
- Property Class navigation — the Component Editor
property_class field exposes separate actions for the Form-level PropertyClassExtensions/<name>.sql file and the IDO Property Class XML. The Form-level action uses the effective forms folder; the IDO-level action uses the optional jeking.mg-ido-pro-editor extension and opens the selected class directly. The field remains fully usable without the IDO Editor extension.
- Selected IDO Property navigation — the Property Editor's read-only IDO Property Details header opens the resolved target IDO in the Mongoose IDO Editor and focuses the exact property currently bound to the form component, including resolved subcollection properties.
- Unified right-side panels — the pinned Component Editor, IDO Usage, Event Graph, and Feature Gates share one compact surface and use Split (side-by-side) or Tabs layouts, set via
slIds.sidePanelLayout (default tabbed); panel widths use shared geometry, Tabs mode uses one equal width, and narrow Split layouts fall back to Tabs regardless of the setting when the main designer no longer fits.
- Menu preview — component
menu_name references resolve against configurable SyteLine Menus/*.sql files, including known CSI/Mongoose product trees when slIds.menusFolder is unset.
Every edit mutates the parsed JSON and re-serializes with the exact SyteLine convention — JSON.stringify(obj, null, 2) with CRLF, no BOM, no trailing newline — so diffs stay clean. Verified byte-for-byte against real forms up to 2.1 MB / 1,724 components.
The webview skips a full rebuild when a state push changes nothing visible (a structural render signature gates re-renders), builds the container tree once per render, and preserves scroll positions. On a 1,724-component form: tree build ≈ 0.6 ms, signature check ≈ 0.6 ms.
Architecture
| Area |
Files |
| JSON round-trip |
src/model/idsJson.ts |
| Model + container tree |
src/model/idsFormModel.ts |
| Enums (mined from 2,466 forms) |
src/model/enums.ts |
| Edit operations + factory |
src/model/editOps.ts, src/model/itemFactory.ts |
| Validation |
src/model/validate.ts |
| Custom editor host |
src/editor/formEditorProvider.ts |
| Webview shell + state |
src/webview/main.ts, appContext.ts, panels.ts, panelShell.ts, signature.ts |
| Views |
src/webview/views/{formTab,layoutTab,tree,preview,props,eventsTab,variablesTab,scriptTab,issuesPanel,featureGatesPanel}.ts |
| Schema tooling |
scripts/mine-schema.js → docs/ids-form-structure.md |
The extension ships a dependency-free MCP server so an MCP-capable agent (e.g. Kiro) can read and
edit IDS/IV2 forms with the same engine the visual designer uses. It reuses the pure model modules, so
edit semantics never diverge between the UI and the agent.
Enable it
- Run the command “IDS Form: Register MCP Server with Kiro” (choose User or Workspace scope). This
writes an entry into
.kiro/settings/mcp.json and, on Windows, a resilient mcp-sl-ids.cmd launcher
next to it.
- Set
slIds.idsRoots to the folder(s) that contain your *.ids.json / *.iv2.json forms (passed
to the server as MG_IDS_ROOTS). Re-run the register command after changing it.
- Reload Kiro to pick up the server. Use “IDS Form: Unregister MCP Server from Kiro” to remove it.
On upgrade the extension self-heals an existing sl-ids-forms registration: activation rewrites the
stale, version-pinned launcher path and reconciles its autoApprove list (adding tools introduced in the
new version — a union that never removes your extras), so you don't have to re-run Register just to pick
up a new tool. Only registrations written by this extension are touched; custom paths are left alone.
Settings
| Setting |
Purpose |
slIds.idsRoots |
Folders searched for forms (MG_IDS_ROOTS). |
slIds.menusFolder |
Optional Menus directory or specific Menus/*.sql file; when unset or invalid, the effective forms folder's Menus directory is indexed first, then workspace-derived CSI/Mongoose product trees are used as per-menu fallbacks. |
slIds.mcpNodePath |
Optional explicit Node executable (instead of the Windows .cmd / Electron-as-Node launcher). |
slIds.mgRest.server / .config / .username |
Optional overrides for the Feature Gates activation lookup; empty reuses the MG REST Client's active profile. |
slIds.mgRest.secretIsToken |
Treat the stored MG REST secret as a security token instead of a password. |
Method-usage commands — slIds.findFormsUsingMethod opens an interactive Markdown report; integrations can call
slIds.findFormsUsingMethodData(ido, method, caseSensitive?) to receive the MethodUsageReport directly without prompts
or UI. Both commands use configured slIds.idsRoots, falling back to the resolved slIds.formsFolder when no roots are set.
Corpus-validation command — slIds.scanForms opens the interactive Problems-panel scan; integrations can call the
Property-usage API — integrations can call slIds.findComponentsBoundToPropertyData(ido, property, options?) to receive a ComponentBindingUsageReport containing every direct IDS/IV2 component binding, absolute form path, variant, component/container metadata, and a serializable layoutNode target. Pass includeSubcollections: true to resolve metadata-backed subcollection bindings. Use the returned target with slIds.selectLayoutNode to open or activate the form and select the control in the designer.
headless slIds.validateAllFormsData(root?) to receive { scanned, forms:[{ form, path, errors, warnings, issues:[{ severity, where, message }], readiness? }], readiness:[{ form, path, pct }] } directly, with no prompts or UI.
forms lists issue-forms worst-first; each .iv2 row and the top-level readiness[] (every scanned .iv2 form) carry the
COUI readiness % — scored baseline-relative to the .ids sibling, matching the Forms Explorer badge (pct 0–100 or
null). It uses configured slIds.idsRoots (falling back to the resolved slIds.formsFolder), or an explicit root.
Shares the validateForm and couiReadiness engines with the designer, so results never diverge.
Tools (58) — read-only form inspectors (form_list, form_get_model, form_validate, form_get_component,
form_get_variable, form_get_section, form_get_notebook, form_get_tree, form_list_events,
form_list_missing_variables) plus form_report_issues (batch-scan the whole corpus and report every form's
validation issues — the corpus-wide form of form_validate, with error/warning/suggestion counts and totals;
json/markdown/html) and form_find_method_usages (scan the configured corpus for one IDO method,
reporting declarative event calls separately from raw form_script Invoke/InvokeIDOMethod calls), a dedicated,
self-describing tool for every one of the designer’s 31
edit operations (add/rename/delete/move/reparent components, sections, notebooks, cards, tabs, variables,
events, form fields), and form_apply_edit as a raw escape hatch.
Also included:
- Compare with Classic —
form_compare_classic (diff one IDS form against its matching classic form)
and form_report_mismatches (batch-scan all forms for component mismatches; json/markdown/html).
- IDS ↔ IV2 (COUI) —
form_compare_ids (structurally diff a form against its .ids/.iv2 sibling),
form_coui_readiness (client-logic migration score, plus a layout-parity section when the sibling exists;
for an .iv2 form it also scores the _IDS IDO rule — every referenced IDO should be the _IDS
variant, with MGCore framework IDOs exempt — and lists the offenders by name;
also exposes structured signals — logicMigrated, per-type formConfig, ground-truth remaining counts, and
optional per-category weights — for an external gating layer),
and form_report_parity (batch-scan all .ids/.iv2 pairs for layout gaps — missing/extra/moved/component_specific;
json/markdown/html). The designer surfaces the same parity in the COUI tab (with per-item / bulk
Adopt from .ids apply-with-preview), and via the “Report IDS↔IV2 Layout Parity” command.
The Forms side panel also badges each .iv2 leaf with its COUI score and, when present, the
validation error/warning counts (e.g. COUI 40% · ✖1 ⚠3; full breakdown in the tooltip), and can be
filtered by that status (“Filter Forms by Status…” — has errors / has warnings / clean / COUI
thresholds, AND-combined with the name filter).
- Global scripts (
Scripts/*.sql) — global_script_list, global_script_get (decode to VB/C# code),
global_script_set (edit code, re-encoded with the original file format preserved; dry-run/apply), and
global_script_search. Point MG_SCRIPTS_ROOTS at the Scripts folder (else the IDS roots are used).
Global-script method resolution is intentionally outside the v1 form_find_method_usages scan, so calls
reached indirectly through RunScript remain a known blind spot.
Safety model
- All mutating tools are dry-run by default and require
apply:true to write; they re-validate after
every change and preserve the exact byte conventions (CRLF/BOM/indent).
- Only the read-only tools are in the registration’s
autoApprove list; every write requires approval.
- Path scope: the server reads/writes any absolute path it is given (there is no workspace sandbox).
This is intentional for a local developer agent — point
slIds.idsRoots at trusted form folders and be
aware that apply:true calls modify files on disk.
Develop
npm install
npm run build # bundle extension + webview
npm test # 79 unit + integration tests
npm run watch # rebuild on change
npm run mine-schema <dir> # profile a folder of *.ids.json
npm run mine-schema <dir> -- --doc docs/ids-form-structure.md
Press F5 to launch an Extension Development Host, then open any *.ids.json.
Not yet implemented
Template (form.template) resolution to show template-provided panes by real name; expression autocomplete for the when rules; multi-select drag.
| |