1
1
import { NavigationPage } from '@/components/navigation/NavigationPage' ;
2
2
import { getParams , setParams as setParamsGlobal } from '@/library/powersync/ConnectionManager' ;
3
- import { Box , Button , Grid , IconButton , styled , TextField } from '@mui/material' ;
3
+ import {
4
+ Box ,
5
+ Button ,
6
+ Grid ,
7
+ IconButton ,
8
+ styled ,
9
+ TextField ,
10
+ Select ,
11
+ MenuItem ,
12
+ InputLabel ,
13
+ FormControl
14
+ } from '@mui/material' ;
4
15
import { FormEvent , useState } from 'react' ;
5
16
import DeleteIcon from '@mui/icons-material/Delete' ;
6
17
import AddIcon from '@mui/icons-material/Add' ;
7
18
8
- const jsonToObjectArray = ( json : Object ) => {
19
+ const typeForValue = ( value : unknown ) => {
20
+ //when using typeof arrays are "object" so we have to have this specific case
21
+ if ( Array . isArray ( value ) ) return 'array' ;
22
+ return typeof value ;
23
+ } ;
24
+
25
+ const jsonToObjectArray = ( json : Object ) : ParameterEntry [ ] => {
9
26
const entrySet = Object . entries ( json ) ;
10
- return entrySet . map ( ( [ key , value ] ) => ( {
11
- key,
12
- value
13
- } ) ) ;
27
+ return entrySet . map ( ( [ key , value ] ) => {
28
+ const type = typeForValue ( value ) as ParameterType ;
29
+ return {
30
+ key,
31
+ // Only arrays and objects need special cases here since JS will take care of the rest.
32
+ value : type === 'array' || type === 'object' ? JSON . stringify ( value ) : String ( value ) ,
33
+ type
34
+ } ;
35
+ } ) ;
36
+ } ;
37
+
38
+ type ParameterType = 'string' | 'number' | 'boolean' | 'array' | 'object' ;
39
+
40
+ interface ParameterEntry {
41
+ key : string ;
42
+ type : ParameterType ;
43
+ value : string ;
44
+ error ?: string ;
45
+ }
46
+
47
+ // A simple set of mappers for converting a string to the correct value for saving
48
+ const CONVERTERS = {
49
+ string : ( v : string ) => v ,
50
+ number : ( v : string ) => Number ( v ) ,
51
+ boolean : ( v : string ) => v === 'true' ,
52
+ array : ( v : string ) => JSON . parse ( v ) ,
53
+ object : ( v : string ) => JSON . parse ( v )
14
54
} ;
15
55
16
56
function ClientParamsPage ( ) {
17
57
const [ params , setParams ] = useState ( jsonToObjectArray ( getParams ( ) ) ) ;
18
58
59
+ const convertValueForSave = ( t : ParameterType , stringValue : string ) => CONVERTERS [ t ] ( stringValue ) ;
60
+
19
61
const onSubmit = ( e : FormEvent < HTMLFormElement > ) => {
20
62
e . preventDefault ( ) ;
21
63
e . stopPropagation ( ) ;
22
64
23
- const newParams = params . reduce ( ( curr , item ) => ( { ...curr , [ `${ item . key } ` ] : item . value } ) , { } ) ;
24
- setParamsGlobal ( newParams ) ;
65
+ try {
66
+ const newParams = params . reduce < Record < string , any > > (
67
+ ( curr : any , item : { key : string ; type : string ; value : string } ) => ( {
68
+ ...curr ,
69
+ [ `${ item . key } ` ] : convertValueForSave ( item . type as ParameterType , item . value )
70
+ } ) ,
71
+ { }
72
+ ) ;
73
+ setParamsGlobal ( newParams ) ;
74
+ } catch ( e ) { }
75
+ } ;
76
+
77
+ const validate = ( val : ParameterEntry ) => {
78
+ if ( val . type == 'object' || val . type == 'array' ) {
79
+ try {
80
+ JSON . parse ( val . value ) ;
81
+ return val ;
82
+ } catch ( e : any ) {
83
+ return {
84
+ ...val ,
85
+ error : e . message
86
+ } ;
87
+ }
88
+ } else {
89
+ return val ;
90
+ }
25
91
} ;
26
92
27
- const replace = ( idx : number , val : any ) => setParams ( ( a ) => a . map ( ( entity , i ) => ( i === idx ? val : entity ) ) ) ;
93
+ const replace = ( idx : number , val : ParameterEntry ) => {
94
+ setParams ( ( a : any [ ] ) => a . map ( ( entity , i ) => ( i === idx ? validate ( val ) : entity ) ) ) ;
95
+ } ;
28
96
29
97
const removeIdx = ( idx : number ) =>
30
- setParams ( ( a ) => a . map ( ( entity , i ) => i !== idx && entity ) . filter ( ( entity ) => entity !== false ) ) ;
98
+ setParams ( ( a : any [ ] ) => a . map ( ( entity , i ) => i !== idx && entity ) . filter ( ( entity ) => entity !== false ) ) ;
31
99
32
100
const addRow = ( ) => {
33
- setParams ( ( a ) => [ ...a , { key : '' , value : '' } ] ) ;
101
+ setParams ( ( a : any [ ] ) => [ ...a , { key : '' , value : '' , type : 'string ' } ] ) ;
34
102
} ;
35
103
36
- const changeValue = ( idx : number , value : string , currKey : string ) => {
37
- replace ( idx , { key : currKey , value } ) ;
104
+ const changeValue = ( idx : number , value : string , currKey : string , type : ParameterType ) => {
105
+ replace ( idx , { key : currKey , value, type } ) ;
38
106
} ;
39
107
40
- const changeKey = ( idx : number , key : string , currValue : unknown ) => {
41
- replace ( idx , { key, value : currValue } ) ;
108
+ const changeKey = ( idx : number , key : string , currValue : string , type : ParameterType ) => {
109
+ replace ( idx , { key, value : currValue , type } ) ;
110
+ } ;
111
+
112
+ const changeType = ( idx : number , key : string , value : string , newType : ParameterType ) => {
113
+ replace ( idx , { key, value, type : newType } ) ;
42
114
} ;
43
115
44
116
return (
45
117
< NavigationPage title = "Client Parameters" >
46
118
< S . MainContainer >
47
119
< form onSubmit = { onSubmit } >
48
- { params . map ( ( { key, value } , idx ) => (
49
- < S . CenteredGrid container >
120
+ { params . map ( ( { key, value, type , error } , idx : number ) => (
121
+ < S . CenteredGrid container key = { idx } >
50
122
< S . CenteredGrid item xs = { 12 } md = { 10 } >
51
123
< TextField
52
124
label = "Key"
53
125
value = { key }
54
126
sx = { { margin : '10px' } }
55
- onChange = { ( v ) => changeKey ( idx , v . target . value , value ) }
127
+ onChange = { ( v : { target : { value : string } } ) => changeKey ( idx , v . target . value , value , type ) }
56
128
/>
129
+ { /* TODO: Potentially add an explanation here about how users should write values for a given piece of text? */ }
57
130
< TextField
58
131
label = "Value"
59
132
value = { value }
60
133
sx = { { margin : '10px' } }
61
- onChange = { ( v ) => changeValue ( idx , v . target . value , key ) }
134
+ error = { ! ! error }
135
+ title = { error }
136
+ onChange = { ( v : { target : { value : string } } ) => changeValue ( idx , v . target . value , key , type ) }
62
137
/>
63
-
138
+ < FormControl sx = { { margin : '10px' , width : '125px' , minWidth : '95px' } } >
139
+ < InputLabel id = "demo-simple-select-label" > Type</ InputLabel >
140
+ < Select
141
+ labelId = "demo-simple-select-label"
142
+ value = { type }
143
+ label = "Type"
144
+ onChange = { ( v : { target : { value : string } } ) =>
145
+ changeType ( idx , key , value , v . target . value as ParameterType )
146
+ } >
147
+ < MenuItem value = { 'string' } > String</ MenuItem >
148
+ < MenuItem value = { 'number' } > Number</ MenuItem >
149
+ < MenuItem value = { 'array' } > Array</ MenuItem >
150
+ < MenuItem value = { 'object' } > Object</ MenuItem >
151
+ < MenuItem value = { 'boolean' } > Boolean</ MenuItem >
152
+ </ Select >
153
+ </ FormControl >
64
154
< IconButton sx = { { margin : '10px' } } color = "error" onClick = { ( ) => removeIdx ( idx ) } >
65
155
< DeleteIcon />
66
156
</ IconButton >
@@ -73,7 +163,7 @@ function ClientParamsPage() {
73
163
</ IconButton >
74
164
</ S . CenteredGrid >
75
165
< Button type = "submit" sx = { { margin : '10px' } } variant = "contained" >
76
- Submit
166
+ Save
77
167
</ Button >
78
168
</ form >
79
169
</ S . MainContainer >
0 commit comments