@@ -800,6 +800,204 @@ export function Form({ schema, onSubmit, initialData = {}, parentConfig }: FormP
800800
801801
802802
803+ // Компонент для редактирования key-value пар (для extraEnv)
804+ function KeyValueEditor ( {
805+ config,
806+ onConfig,
807+ onBack,
808+ title,
809+ description
810+ } : {
811+ config : Record < string , string > ;
812+ onConfig : ( newConfig : Record < string , string > ) => void ;
813+ onBack : ( ) => void ;
814+ title ?: string ;
815+ description ?: string ;
816+ } ) {
817+ const [ pairs , setPairs ] = useState < Array < { key : string ; value : string } > > ( ( ) => {
818+ return Object . entries ( config ) . map ( ( [ key , value ] ) => ( { key, value } ) ) ;
819+ } ) ;
820+ const [ editingIndex , setEditingIndex ] = useState < number | null > ( null ) ;
821+ const [ newKey , setNewKey ] = useState ( '' ) ;
822+ const [ newValue , setNewValue ] = useState ( '' ) ;
823+ const [ mode , setMode ] = useState < 'list' | 'add' | 'edit' > ( 'list' ) ;
824+ const [ addField , setAddField ] = useState < 'key' | 'value' > ( 'key' ) ;
825+ const [ tempKey , setTempKey ] = useState ( '' ) ;
826+ const [ tempValue , setTempValue ] = useState ( '' ) ;
827+
828+ // Синхронизируем pairs с config при изменении config извне
829+ // Но только если мы не в режиме редактирования/добавления, чтобы не потерять изменения
830+ useEffect ( ( ) => {
831+ if ( mode === 'list' ) {
832+ const newPairs = Object . entries ( config ) . map ( ( [ key , value ] ) => ( { key, value } ) ) ;
833+ setPairs ( newPairs ) ;
834+ }
835+ } , [ config , mode ] ) ;
836+
837+ useInput ( ( input , key ) => {
838+ if ( key . escape ) {
839+ if ( mode === 'add' || mode === 'edit' ) {
840+ setMode ( 'list' ) ;
841+ setNewKey ( '' ) ;
842+ setNewValue ( '' ) ;
843+ setTempKey ( '' ) ;
844+ setTempValue ( '' ) ;
845+ setAddField ( 'key' ) ;
846+ setEditingIndex ( null ) ;
847+ } else {
848+ onBack ( ) ;
849+ }
850+ }
851+ } ) ;
852+
853+ const savePairs = ( updatedPairs : Array < { key : string ; value : string } > ) => {
854+ const newConfig : Record < string , string > = { } ;
855+ updatedPairs . forEach ( ( { key, value } ) => {
856+ if ( key . trim ( ) ) {
857+ newConfig [ key . trim ( ) ] = value ;
858+ }
859+ } ) ;
860+ onConfig ( newConfig ) ;
861+ setPairs ( updatedPairs ) ;
862+ } ;
863+
864+ if ( mode === 'add' ) {
865+ if ( addField === 'key' ) {
866+ return (
867+ < Box flexDirection = "column" gap = { 1 } >
868+ < Text color = "cyan" > { title || 'Extra Environment Variables' } </ Text >
869+ { description && < Text color = "gray" > { description } </ Text > }
870+ < Text color = "yellow" > Adding new variable (Escape to cancel)</ Text >
871+ < Text color = "cyan" > Variable name:</ Text >
872+ < TextInput
873+ key = { `add-key-input` }
874+ defaultValue = { tempKey }
875+ onChange = { setTempKey }
876+ onSubmit = { ( value ) => {
877+ if ( value . trim ( ) ) {
878+ setNewKey ( value . trim ( ) ) ;
879+ setTempKey ( value . trim ( ) ) ;
880+ setAddField ( 'value' ) ;
881+ }
882+ } }
883+ placeholder = "e.g., ANTHROPIC_API_KEY"
884+ />
885+ < Text color = "gray" > Press Enter to continue to value field</ Text >
886+ </ Box >
887+ ) ;
888+ }
889+
890+ return (
891+ < Box flexDirection = "column" gap = { 1 } >
892+ < Text color = "cyan" > { title || 'Extra Environment Variables' } </ Text >
893+ < Text color = "yellow" > Adding: { tempKey } (Escape to cancel)</ Text >
894+ < Text color = "cyan" > Variable value:</ Text >
895+ < TextInput
896+ key = { `add-value-input` }
897+ defaultValue = { tempValue }
898+ onChange = { setTempValue }
899+ onSubmit = { ( value ) => {
900+ if ( tempKey . trim ( ) ) {
901+ // Убеждаемся, что мы добавляем к текущим pairs, а не перезаписываем
902+ const currentPairs = pairs . length > 0 ? pairs : Object . entries ( config ) . map ( ( [ key , val ] ) => ( { key, value : val } ) ) ;
903+ const updated = [ ...currentPairs , { key : tempKey . trim ( ) , value : value || '' } ] ;
904+ savePairs ( updated ) ;
905+ setNewKey ( '' ) ;
906+ setNewValue ( '' ) ;
907+ setTempKey ( '' ) ;
908+ setTempValue ( '' ) ;
909+ setAddField ( 'key' ) ;
910+ setMode ( 'list' ) ;
911+ }
912+ } }
913+ placeholder = "Enter value"
914+ />
915+ < Text color = "gray" > Press Enter to save</ Text >
916+ </ Box >
917+ ) ;
918+ }
919+
920+ if ( mode === 'edit' && editingIndex !== null ) {
921+ const pair = pairs [ editingIndex ] ;
922+ return (
923+ < Box flexDirection = "column" gap = { 1 } >
924+ < Text color = "cyan" > { title || 'Extra Environment Variables' } </ Text >
925+ < Text color = "yellow" > Editing: { pair . key } (Escape to cancel)</ Text >
926+ < Text color = "cyan" > Variable name:</ Text >
927+ < TextInput
928+ key = { `edit-key-${ editingIndex } ` }
929+ defaultValue = { newKey }
930+ onChange = { setNewKey }
931+ placeholder = { pair . key }
932+ />
933+ < Text color = "cyan" > Variable value:</ Text >
934+ < TextInput
935+ key = { `edit-value-${ editingIndex } ` }
936+ defaultValue = { newValue }
937+ onChange = { setNewValue }
938+ onSubmit = { ( ) => {
939+ const updated = [ ...pairs ] ;
940+ updated [ editingIndex ] = { key : newKey . trim ( ) || pair . key , value : newValue } ;
941+ savePairs ( updated ) ;
942+ setEditingIndex ( null ) ;
943+ setNewKey ( '' ) ;
944+ setNewValue ( '' ) ;
945+ setMode ( 'list' ) ;
946+ } }
947+ placeholder = { pair . value }
948+ />
949+ </ Box >
950+ ) ;
951+ }
952+
953+ const options = [
954+ { label : '< back' , value : 'back' } ,
955+ ...pairs . map ( ( pair , index ) => ( {
956+ label : `${ pair . key } =${ pair . value . length > 30 ? pair . value . substring ( 0 , 30 ) + '...' : pair . value } ` ,
957+ value : `edit-${ index } `
958+ } ) ) ,
959+ ...( pairs . length > 0 ? pairs . map ( ( pair , index ) => ( {
960+ label : `🗑️ delete ${ pair . key } ` ,
961+ value : `delete-${ index } `
962+ } ) ) : [ ] ) ,
963+ { label : '+ add variable' , value : 'add' }
964+ ] ;
965+
966+ return (
967+ < Box flexDirection = "column" gap = { 1 } >
968+ < Text color = "cyan" > { title || 'Extra Environment Variables' } </ Text >
969+ { description && < Text color = "gray" > { description } </ Text > }
970+ < Text color = "gray" > Variables: { pairs . length } </ Text >
971+ < Select
972+ options = { options }
973+ onChange = { ( value ) => {
974+ if ( value === 'back' ) {
975+ onBack ( ) ;
976+ } else if ( value === 'add' ) {
977+ setNewKey ( '' ) ;
978+ setNewValue ( '' ) ;
979+ setTempKey ( '' ) ;
980+ setTempValue ( '' ) ;
981+ setAddField ( 'key' ) ;
982+ setMode ( 'add' ) ;
983+ } else if ( value . startsWith ( 'edit-' ) ) {
984+ const index = parseInt ( value . split ( '-' ) [ 1 ] ) ;
985+ const pair = pairs [ index ] ;
986+ setEditingIndex ( index ) ;
987+ setNewKey ( pair . key ) ;
988+ setNewValue ( pair . value ) ;
989+ setMode ( 'edit' ) ;
990+ } else if ( value . startsWith ( 'delete-' ) ) {
991+ const index = parseInt ( value . split ( '-' ) [ 1 ] ) ;
992+ const updated = pairs . filter ( ( _ , i ) => i !== index ) ;
993+ savePairs ( updated ) ;
994+ }
995+ } }
996+ />
997+ </ Box >
998+ ) ;
999+ }
1000+
8031001// Универсальный компонент для добавления нового ключа
8041002function AddNewKey ( { schema, defaultKeys, onAdd, onBack } : {
8051003 schema : z . ZodSchema ;
@@ -980,6 +1178,25 @@ function KeysList({
9801178 ) ;
9811179 }
9821180
1181+ // Специальная обработка для extra-env-config (key-value pairs)
1182+ const extraEnvSchemaMeta = ( addSchema as any ) . meta ? ( addSchema as any ) . meta ( ) : { } ;
1183+ if ( extraEnvSchemaMeta . type === 'extra-env-config' ) {
1184+ return (
1185+ < KeyValueEditor
1186+ key = { `keyvalue-${ selectedKey } ` }
1187+ config = { config [ selectedKey ] || { } }
1188+ onConfig = { ( newKeyValuePairs ) => {
1189+ const updatedConfig = { ...config , [ selectedKey ] : newKeyValuePairs } ;
1190+ onConfig ( updatedConfig ) ;
1191+ setSelectedKey ( null ) ;
1192+ } }
1193+ onBack = { ( ) => setSelectedKey ( null ) }
1194+ title = { extraEnvSchemaMeta . title || 'Extra Environment Variables' }
1195+ description = { extraEnvSchemaMeta . description }
1196+ />
1197+ ) ;
1198+ }
1199+
9831200 // Для остальных схем используем Form
9841201 return (
9851202 < Box flexDirection = "column" gap = { 1 } >
0 commit comments