perf(json-editor): unify admin JSON editing experience (#6421)

* perf(json-editor): improve JSON editing experience

- integrate Yace for syntax highlighting, history, indentation, auto-closing, and smart line breaks.
- add copy support, cursor location feedback, and synchronized content and line-number scrolling.
- extract JSON editor utilities and cover key interactions with unit tests.

* perf(system-settings): improve JSON configuration editing

- replace raw JSON textareas with the shared editor for highlighting, validation, copy, and formatting.
- preserve field-specific examples and make placeholders visible through the transparent editor layer.
- remove duplicate formatting controls while keeping existing form validation and save behavior.

* perf(json-editor): standardize JSON inputs across admin settings

- replace pure JSON textareas with the shared editor across system settings and channel workflows.
- preserve form focus, validation, placeholders, and visual or JSON editing modes.
- add happy-dom component coverage for form bindings, controlled updates, and formatting.

* fix(json-code-editor): address accessibility review findings

- Drop the unconditional aria-label that overrode every field's
  label-derived accessible name; add an optional ariaLabel prop and
  set it at call sites without an associated label
- Associate standalone Labels via htmlFor/id in channel-affinity views
- Hide the highlight mirror and line-number layers from the
  accessibility tree (aria-hidden)
- Give the line-number gutter an opaque background so horizontally
  scrolled code no longer slides under it
- Degrade to no scroll sync instead of destroying the editor when the
  line-number layer is not found
This commit is contained in:
QuentinHsu
2026-07-25 19:10:28 +08:00
committed by GitHub
parent 18b0b7631a
commit eb4a1bd193
28 changed files with 1089 additions and 419 deletions
@@ -31,6 +31,7 @@ import {
sideDrawerFormClassName,
sideDrawerHeaderClassName,
} from '@/components/drawer-layout'
import { JsonCodeEditor } from '@/components/json-code-editor'
import { MultiSelect } from '@/components/multi-select'
import { Button } from '@/components/ui/button'
import {
@@ -59,7 +60,6 @@ import {
SheetHeader,
SheetTitle,
} from '@/components/ui/sheet'
import { Textarea } from '@/components/ui/textarea'
import {
checkClusterNameAvailability,
@@ -702,10 +702,14 @@ export function CreateDeploymentDrawer({
<FormItem>
<FormLabel>{t('Environment variables (JSON)')}</FormLabel>
<FormControl>
<Textarea
className='min-h-24 font-mono text-xs'
<JsonCodeEditor
value={field.value || ''}
onChange={field.onChange}
name={field.name}
onBlur={field.onBlur}
textareaRef={field.ref}
placeholder='{"KEY":"VALUE"}'
{...field}
heightClassName='h-40 min-h-40 max-h-40'
/>
</FormControl>
<FormMessage />
@@ -722,10 +726,14 @@ export function CreateDeploymentDrawer({
{t('Secret environment variables (JSON)')}
</FormLabel>
<FormControl>
<Textarea
className='min-h-24 font-mono text-xs'
<JsonCodeEditor
value={field.value || ''}
onChange={field.onChange}
name={field.name}
onBlur={field.onBlur}
textareaRef={field.ref}
placeholder='{"SECRET":"VALUE"}'
{...field}
heightClassName='h-40 min-h-40 max-h-40'
/>
</FormControl>
<FormMessage />
@@ -26,6 +26,7 @@ import { toast } from 'sonner'
import { z } from 'zod'
import { Dialog } from '@/components/dialog'
import { JsonCodeEditor } from '@/components/json-code-editor'
import { Button } from '@/components/ui/button'
import {
Collapsible,
@@ -41,7 +42,6 @@ import {
FormMessage,
} from '@/components/ui/form'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { getDeployment, updateDeployment } from '../../api'
import { deploymentsQueryKeys } from '../../lib'
@@ -398,10 +398,14 @@ export function UpdateConfigDialog({
<FormItem>
<FormLabel>{t('Env (JSON object)')}</FormLabel>
<FormControl>
<Textarea
className='min-h-40 font-mono text-xs'
<JsonCodeEditor
value={field.value || ''}
onChange={field.onChange}
name={field.name}
onBlur={field.onBlur}
textareaRef={field.ref}
placeholder='{"KEY":"VALUE"}'
{...field}
heightClassName='h-40 min-h-40 max-h-40'
/>
</FormControl>
<FormMessage />
@@ -415,10 +419,14 @@ export function UpdateConfigDialog({
<FormItem>
<FormLabel>{t('Secret env (JSON object)')}</FormLabel>
<FormControl>
<Textarea
className='min-h-40 font-mono text-xs'
<JsonCodeEditor
value={field.value || ''}
onChange={field.onChange}
name={field.name}
onBlur={field.onBlur}
textareaRef={field.ref}
placeholder='{"SECRET":"VALUE"}'
{...field}
heightClassName='h-40 min-h-40 max-h-40'
/>
</FormControl>
<FormMessage />