Skip to content

feat(ui, server): Intuitive JSON editing for Controls#151

Merged
lan17 merged 57 commits intomainfrom
lev/improvejsoneditor
Apr 7, 2026
Merged

feat(ui, server): Intuitive JSON editing for Controls#151
lan17 merged 57 commits intomainfrom
lev/improvejsoneditor

Conversation

@lan17
Copy link
Copy Markdown
Contributor

@lan17 lan17 commented Mar 27, 2026

Summary

  • What changed and why.

Scope

  • User-facing/API changes:
  • Internal changes:
  • Out of scope:

Risk and Rollout

  • Risk level: low / medium / high
  • Rollback plan:

Testing

  • Added or updated automated tests
  • Ran make check (or explained why not)
  • Manually verified behavior

Checklist

  • Linked issue/spec (if applicable)
  • Updated docs/examples for user-facing changes
  • Included any required follow-up tasks

lan17 added 5 commits March 27, 2026 12:24
- Replace custom suggestion panel with Monaco's native autocomplete
- Fix mount race condition for completion provider registration
- Add schema-aware suggestions for evaluator names, selector paths, enums
- Auto-trigger suggestions on cursor entering string values and blank lines
- Add inline value hints showing valid options for empty fields
- Auto-update evaluator config when evaluator name changes
- Auto-add/remove steering_context when decision changes to/from "steer"
- Auto-fix missing and trailing commas with debounced correction
- Add condition code actions (Ctrl+.): wrap in AND/OR/NOT, add condition, convert
- Add format and copy-to-clipboard toolbar buttons
- Dark theme support via DOM attribute detection
- Bracket colorization, guides, sticky scroll, folding, smooth animations
- Prevent Escape from closing modal (only dismisses suggest widget)
- Default SSN regex example template for new controls
- Rename "From JSON" to "Write your own"
- Clean up: deduplicate code action builders, merge content listeners, remove dead code
- Use alias name for GetControlSchemaResponse constructor (mypy expects alias)
- Add populate_by_name config to allow both field name and alias
- Run prettier on all changed UI files
@codecov
Copy link
Copy Markdown

codecov bot commented Mar 27, 2026

Codecov Report

❌ Patch coverage is 86.66667% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
models/src/agent_control_models/controls.py 77.77% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

lan17 added 24 commits March 27, 2026 15:11
Merge 3 separate onDidChangeModelContent listeners into one unified
handler that shares state and avoids redundant JSON parsing. Remove
suppressCommaFixRef hack in favor of a local closure variable. Extract
isSuggestWidgetVisible and reformatIfValid helpers.
- Don't show value suggestions (like "null") at property key positions
- Only apply comma fix + reformat when result is valid JSON
- Prevents corruption when user is mid-edit inside a string value
- Remove auto-reformat on debounce — formatting is now explicit (Format button only)
- Comma auto-fix only runs when editor loses focus (not while user is typing)
- Comma fix only applies if result is valid JSON
- Clamp cursor after replaceAllContent to prevent invalid lineNumber
- Wrap cursor listener in try-catch for undo edge case
- Remove forceMoveMarkers to avoid stale cursor positions in undo stack
- Change step_types from Literal["tool","llm"] to list[str] with examples
- Disable quickSuggestions for strings (was triggering on every keystroke)
- Only auto-trigger suggestions on explicit cursor navigation (click/arrows),
  not on typing (CursorChangeReason.Explicit only)
- Code actions now replace full document for clean undo + proper formatting
- Disable quickSuggestions and suggestOnTriggerCharacters entirely
- All suggestion triggering is now controlled by our cursor listener
- Only auto-trigger for: blank lines (property suggestions) and
  short strings ≤2 chars (enum/path/evaluator browsing)
- Typing in long strings never shows popups
- contentJustChanged only flags small single-char edits as "typing"
- Re-enable suggestOnTriggerCharacters so typing " triggers property suggestions
- Re-add fixedOverflowWidgets to prevent suggest widget clipping at editor top
- Keep quickSuggestions disabled to prevent "No suggestions" popup while typing
- contentJustChanged only flags small single-char edits (not setValue/reformat)
- Re-enable suggestOnTriggerCharacters so typing " triggers property suggestions
- Remove fixedOverflowWidgets (causes mispositioning in modals)
- Add domain field pattern matching: auto-trigger for name, path, decision,
  execution fields regardless of string length
- Description/pattern/other free-text fields don't auto-trigger
- Restrict value suggestions to actual string value positions only
  (isStringValueContext must be true) — not blank lines or brackets
- Filter null from preferred values (Pydantic nullable fields)
- Remove overflow:clip from editor container (caused widget clipping)
- Restore schema in diagnostics for validation squiggles
- Remove dead setModeConfiguration code (doesn't work in Monaco 0.55)
siddhant-galileo and others added 14 commits April 6, 2026 11:50
## Summary
- What changed and why.

Updated to use codemirror instead of monaco. 



https://github.com/user-attachments/assets/3d9bac1d-e0de-449f-83ed-e0606ee34271



## Scope
- User-facing/API changes:
- Internal changes:
- Out of scope:

## Risk and Rollout
- Risk level: low / medium / high
- Rollback plan:

## Testing
- [ ] Added or updated automated tests
- [ ] Ran `make check` (or explained why not)
- [ ] Manually verified behavior

## Checklist
- [ ] Linked issue/spec (if applicable)
- [ ] Updated docs/examples for user-facing changes
- [ ] Included any required follow-up tasks
- Show Mantine validation error for empty control name instead of silently
  blocking via HTML5 required attribute
- Close confirm modal immediately on click to prevent double-submit race
  that caused 409 Conflict errors
- Only disable Form/JSON toggle on JSON parse errors, not server validation
  errors, preventing a stuck-state where both toggles were disabled
- Preserve user-edited control name when syncing workingDefinition to form
  during mode switches
The HTML5 required attribute silently blocked form submission before
Mantine's onSubmit validation could run, hiding the "Control name is
required" error. Adding noValidate lets Mantine handle validation and
display the error text on the input field.
…nippet

When accepting a property completion for a string field (e.g.
"description"), the snippet inserted literal "" with the cursor after
the closing quote. The user's subsequent typing ended up outside the
string value. Use a snippet tab stop ($1) between the quotes so the
cursor lands inside for immediate typing.
- Suppress Monaco's built-in "$schema" completion by passing a minimal
  schema with additionalProperties:true to setDiagnosticsOptions and
  disabling the built-in completion provider via setModeConfiguration
- Auto-trigger property suggestions when user types `"` at a property-key
  position (blank line or after comma), improving discoverability
A. Move validation error alert above the editor so it's visible without
   scrolling — previously hidden below the 520px editor height.

B. Add inline error highlighting in Monaco: server validation errors now
   show a red wavy underline on the offending value with hover messages.
   Uses deltaDecorations to highlight the JSON path from error field.

C. Show all enum values when cursor is inside an existing value. Setting
   filterText to the current node value bypasses Monaco's fuzzy matching,
   so "allow", "steer", "warn", "log" all appear even when cursor is in
   "deny".
D. Cancel with unsaved changes in edit mode now shows a "Discard
   unsaved changes?" confirmation dialog before closing.

F. Cmd+S / Ctrl+S keyboard shortcut triggers Save from anywhere in
   the edit dialog via formRef.requestSubmit().

G. Step name placeholder changed from "No steps available" to
   "No steps registered via SDK" for better guidance.

H. Added tooltip on Form/Full JSON toggle explaining the two modes.

J. Shortened default control names from "list-control-for-agent-name"
   to "new-list-control".

Also adds UX_AUDIT.md to track remaining improvements.
@lan17 lan17 changed the title feat(ui): Intuitive JSON editing for Controls feat(ui, server): Intuitive JSON editing for Controls Apr 6, 2026
lan17 added 10 commits April 6, 2026 15:35
The dirty check only ran on Cancel button click. The Modal X button
called onClose directly, bypassing the check. Added an onCloseRef
prop so EditControlContent can expose its handleClose (with dirty
check) to the parent Modal's onClose handler.
definitionForm.isDirty() returned true immediately after opening the
edit dialog because setValues makes the form dirty relative to
initialValues. Call resetDirty(syncedValues) after setValues so the
form only reports dirty when the user actually edits something.

Fixes the "closing edit modal removes query parameters" integration
test which clicked Cancel and expected the modal to close immediately.
…ved check

form.isDirty() was unreliable because setValues in the sync effect made
it return true before the user touched anything. Replaced with an
explicit isDirty state flag that is:
- set via onValuesChange (gated behind formSyncedRef to skip initial sync)
- set via handleDefinitionJsonChange for JSON mode edits
- reset when the control prop changes (dialog reopen)
…esChange

Mantine's onValuesChange fires on programmatic setValues calls, causing
false dirty state. The native DOM onChange event on <form> only fires
from actual user interactions (typing, selecting), making it reliable
for dirty tracking without timing hacks.
Mantine components dispatch synthetic change events during init, making
form-level onChange unreliable for dirty tracking. Simplify to only
track isDirty from handleDefinitionJsonChange (JSON editor edits).
Form mode Cancel always closes immediately since form edits haven't
been persisted and the control data is still available on reopen.
…o limitation

model.applyEdits desynchronizes the main thread model from the web
worker, causing "Cannot read properties of undefined (reading
'substring')" crashes. Reverted to queueMicrotask + executeEdits.

The async boundary means auto-edits (evaluator config fill, steering
context) create separate undo groups, which breaks redo after undo.
This is a known Monaco limitation — undo still works correctly.
@lan17 lan17 merged commit 8c23cef into main Apr 7, 2026
5 checks passed
@lan17 lan17 deleted the lev/improvejsoneditor branch April 7, 2026 02:59
galileo-automation pushed a commit that referenced this pull request Apr 7, 2026
## [2.2.0](ts-sdk-v2.1.0...ts-sdk-v2.2.0) (2026-04-07)

### Features

* **evaluators:** add starts_with/ends_with mode to list evaluator ([#154](#154)) ([bf1f7d7](bf1f7d7))
* **sdk:** [Enterprise Integration]: Add provider agnostic traceing ([#145](#145)) ([f1ca27c](f1ca27c))
* **sdk:** Add telemetry package to support sinks ([#164](#164)) ([2186ba1](2186ba1))
* **sdk:** default merge events in SDK ([#155](#155)) ([5984a60](5984a60))
* **server,sdk, ui:** Control Templates ([#158](#158)) ([78bb538](78bb538))
* **server:** Override PG password in dockerfile ([#148](#148)) ([5d70c7d](5d70c7d))
* **server:** Remove container name for dev postgres ([92b2d13](92b2d13))
* **server:** Start local dev pg under docker compose project endign with dev ([88bee63](88bee63))
* **ui, server:** Intuitive JSON editing for Controls ([#151](#151)) ([8c23cef](8c23cef))
* **ui:** add full control JSON editing and create-from-JSON ([#147](#147)) ([e685ed0](e685ed0))

### Bug Fixes

* **docs:** add explicit shutdown to quickstart example ([#149](#149)) ([b76014f](b76014f))
* **sdk:** use sync shutdown flush fallback ([#150](#150)) ([90265ba](90265ba))
* **server:**  remove unused evaluator config store ([#152](#152)) ([dea2873](dea2873))
* **server:** Omit null fields in control JSON editor ([#157](#157)) ([0aa2f3c](0aa2f3c))
* **server:** Update docker-compose.dev.yml to use different container name ([14d4c87](14d4c87))
* **ui:** improve edit control ux, no layout shift, consistent spacing ([#122](#122)) ([76d67b9](76d67b9))
@galileo-automation
Copy link
Copy Markdown
Collaborator

🎉 This PR is included in version 2.2.0 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants