@@ -5,6 +5,7 @@ import { Loader2 } from 'lucide-react'
55import { Dialog , DialogContent , DialogHeader , DialogFooter , DialogTitle } from '@/components/ui/dialog'
66import type { OpenCodeConfig } from '@/api/types/settings'
77import { parseJsonc } from '@/lib/jsonc'
8+ import { FetchError } from '@/api/fetchWrapper'
89
910interface OpenCodeConfigEditorProps {
1011 config : OpenCodeConfig | null
@@ -44,28 +45,46 @@ export function OpenCodeConfigEditor({
4445 if ( ! config ) return
4546
4647 try {
47- const parsedContent = parseJsonc < Record < string , unknown > > ( editConfigContent )
48-
49- const forbiddenFields = [ 'id' , 'createdAt' , 'updatedAt' ]
50- const foundForbidden = forbiddenFields . filter ( field => field in parsedContent )
51- if ( foundForbidden . length > 0 ) {
52- throw new Error ( `Invalid fields found: ${ foundForbidden . join ( ', ' ) } . These fields are managed automatically.` )
53- }
54-
48+ parseJsonc < Record < string , unknown > > ( editConfigContent )
5549 await onUpdate ( editConfigContent )
5650 onClose ( )
5751 } catch ( error ) {
5852 if ( error instanceof SyntaxError ) {
59- const match = error . message . match ( / l i n e ( \d + ) / i)
60- const line = match ? parseInt ( match [ 1 ] ) : null
53+ const lineMatch = error . message . match ( / l i n e \s + ( \d + ) / i)
54+ const line = lineMatch ? parseInt ( lineMatch [ 1 ] ) : null
6155 setEditErrorLine ( line )
62- setEditError ( 'Invalid JSON/JSONC format' )
56+ if ( line && editTextareaRef . current ) {
57+ highlightErrorLine ( editTextareaRef . current , line )
58+ }
59+ setEditError ( `Invalid JSON/JSONC: ${ error . message } ` )
60+ } else if ( error instanceof FetchError ) {
61+ setEditError ( error . detail || error . message )
62+ } else if ( error instanceof Error ) {
63+ setEditError ( error . message )
6364 } else {
64- setEditError ( 'Failed to save. Please check your changes and try again. ' )
65+ setEditError ( 'Failed to save configuration ' )
6566 }
6667 }
6768 }
6869
70+ const highlightErrorLine = ( textarea : HTMLTextAreaElement , line : number ) => {
71+ const lines = textarea . value . split ( '\n' )
72+ if ( line > lines . length ) return
73+
74+ let charIndex = 0
75+ for ( let i = 0 ; i < line - 1 ; i ++ ) {
76+ charIndex += lines [ i ] . length + 1
77+ }
78+
79+ textarea . focus ( )
80+ textarea . setSelectionRange ( charIndex , charIndex + lines [ line - 1 ] . length )
81+
82+ // Scroll to make the error line visible
83+ const lineHeight = textarea . scrollHeight / lines . length
84+ const targetPosition = lineHeight * ( line - 1 )
85+ textarea . scrollTop = targetPosition - textarea . clientHeight / 2 + lineHeight / 2
86+ }
87+
6988 if ( ! config ) return null
7089
7190 return (
@@ -87,7 +106,7 @@ export function OpenCodeConfigEditor({
87106 setEditError ( '' )
88107 setEditErrorLine ( null )
89108 } }
90- className = " flex-1 font-mono text-[16px] sm:text-xs md:text-sm resize-none h-full rounded-none sm:rounded-md"
109+ className = { ` flex-1 font-mono text-[16px] sm:text-xs md:text-sm resize-none h-full rounded-none sm:rounded-md ${ editErrorLine ? 'error-highlight' : '' } ` }
91110 />
92111 { editError && (
93112 < div className = "absolute bottom-0 left-0 right-0 bg-background/95 border-t p-2 sm:p-3" >
0 commit comments