From 7a51853b176e8149d77f33d7ec3cb3c03432bf34 Mon Sep 17 00:00:00 2001 From: Ry Anderson Date: Fri, 8 Nov 2024 00:09:30 +0000 Subject: [PATCH 1/5] Add initial type support for param defs --- .../src/app/views/client-params.tsx | 78 +++++++++++++++---- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/tools/diagnostics-app/src/app/views/client-params.tsx b/tools/diagnostics-app/src/app/views/client-params.tsx index 4696f305..cbf4c0a1 100644 --- a/tools/diagnostics-app/src/app/views/client-params.tsx +++ b/tools/diagnostics-app/src/app/views/client-params.tsx @@ -1,26 +1,59 @@ import { NavigationPage } from '@/components/navigation/NavigationPage'; import { getParams, setParams as setParamsGlobal } from '@/library/powersync/ConnectionManager'; -import { Box, Button, Grid, IconButton, styled, TextField } from '@mui/material'; +import { + Box, + Button, + Grid, + IconButton, + styled, + TextField, + Select, + MenuItem, + InputLabel, + FormControl +} from '@mui/material'; import { FormEvent, useState } from 'react'; import DeleteIcon from '@mui/icons-material/Delete'; import AddIcon from '@mui/icons-material/Add'; +const typeForValue = (value: unknown) => { + if (Array.isArray(value)) return 'array'; + return typeof value; +}; + const jsonToObjectArray = (json: Object) => { const entrySet = Object.entries(json); - return entrySet.map(([key, value]) => ({ - key, - value - })); + return entrySet.map(([key, value]) => { + const type = typeForValue(value); + return { + key, + value: type === 'array' || type === 'object' ? JSON.stringify(value) : value, + type + }; + }); +}; + +const CONVERTERS = { + string: (v) => v, + number: (v) => Number(v), + boolean: (v) => v === 'true', + array: (v) => JSON.parse(v), + object: (v) => JSON.parse(v) }; function ClientParamsPage() { const [params, setParams] = useState(jsonToObjectArray(getParams())); + const convertValueForSave = (t, stringValue: string) => CONVERTERS[t](stringValue); + const onSubmit = (e: FormEvent) => { e.preventDefault(); e.stopPropagation(); - const newParams = params.reduce((curr, item) => ({ ...curr, [`${item.key}`]: item.value }), {}); + const newParams = params.reduce( + (curr, item) => ({ ...curr, [`${item.key}`]: convertValueForSave(item.type, item.value) }), + {} + ); setParamsGlobal(newParams); }; @@ -33,34 +66,51 @@ function ClientParamsPage() { setParams((a) => [...a, { key: '', value: '' }]); }; - const changeValue = (idx: number, value: string, currKey: string) => { - replace(idx, { key: currKey, value }); + const changeValue = (idx: number, value: string, currKey: string, type: string) => { + replace(idx, { key: currKey, value, type }); + }; + + const changeKey = (idx: number, key: string, currValue: unknown, type: string) => { + replace(idx, { key, value: currValue, type }); }; - const changeKey = (idx: number, key: string, currValue: unknown) => { - replace(idx, { key, value: currValue }); + const changeType = (idx: number, key: string, value: unknown, newType: string) => { + replace(idx, { key, value, type: newType }); }; return (
- {params.map(({ key, value }, idx) => ( + {params.map(({ key, value, type }: { key: string; value: string; type: string }, idx: number) => ( changeKey(idx, v.target.value, value)} + onChange={(v: { target: { value: string } }) => changeKey(idx, v.target.value, value, type)} /> changeValue(idx, v.target.value, key)} + onChange={(v: { target: { value: string } }) => changeValue(idx, v.target.value, key, type)} /> - + + Type + + removeIdx(idx)}> From f8f3e4af1f7951bd64fe99d946b2c1b6cd9043b3 Mon Sep 17 00:00:00 2001 From: Ry Anderson Date: Fri, 8 Nov 2024 00:15:15 +0000 Subject: [PATCH 2/5] Fix typings --- .../src/app/views/client-params.tsx | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/tools/diagnostics-app/src/app/views/client-params.tsx b/tools/diagnostics-app/src/app/views/client-params.tsx index cbf4c0a1..9a299209 100644 --- a/tools/diagnostics-app/src/app/views/client-params.tsx +++ b/tools/diagnostics-app/src/app/views/client-params.tsx @@ -34,36 +34,40 @@ const jsonToObjectArray = (json: Object) => { }; const CONVERTERS = { - string: (v) => v, - number: (v) => Number(v), - boolean: (v) => v === 'true', - array: (v) => JSON.parse(v), - object: (v) => JSON.parse(v) + string: (v: string) => v, + number: (v: string) => Number(v), + boolean: (v: string) => v === 'true', + array: (v: string) => JSON.parse(v), + object: (v: string) => JSON.parse(v) }; function ClientParamsPage() { const [params, setParams] = useState(jsonToObjectArray(getParams())); - const convertValueForSave = (t, stringValue: string) => CONVERTERS[t](stringValue); + const convertValueForSave = (t: 'string' | 'number' | 'boolean' | 'array' | 'object', stringValue: string) => + CONVERTERS[t](stringValue); const onSubmit = (e: FormEvent) => { e.preventDefault(); e.stopPropagation(); const newParams = params.reduce( - (curr, item) => ({ ...curr, [`${item.key}`]: convertValueForSave(item.type, item.value) }), + (curr: any, item: { key: any; type: 'string' | 'number' | 'boolean' | 'array' | 'object'; value: string }) => ({ + ...curr, + [`${item.key}`]: convertValueForSave(item.type, item.value) + }), {} ); setParamsGlobal(newParams); }; - const replace = (idx: number, val: any) => setParams((a) => a.map((entity, i) => (i === idx ? val : entity))); + const replace = (idx: number, val: any) => setParams((a: any[]) => a.map((entity, i) => (i === idx ? val : entity))); const removeIdx = (idx: number) => - setParams((a) => a.map((entity, i) => i !== idx && entity).filter((entity) => entity !== false)); + setParams((a: any[]) => a.map((entity, i) => i !== idx && entity).filter((entity) => entity !== false)); const addRow = () => { - setParams((a) => [...a, { key: '', value: '' }]); + setParams((a: any[]) => [...a, { key: '', value: '' }]); }; const changeValue = (idx: number, value: string, currKey: string, type: string) => { @@ -108,7 +112,7 @@ function ClientParamsPage() { Number Array Object - boolean + Boolean removeIdx(idx)}> From 5f5155845e1451cfe5363060800e529f9bff8382 Mon Sep 17 00:00:00 2001 From: Ry Anderson Date: Fri, 8 Nov 2024 00:19:58 +0000 Subject: [PATCH 3/5] Add Type Convertion comments --- tools/diagnostics-app/src/app/views/client-params.tsx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tools/diagnostics-app/src/app/views/client-params.tsx b/tools/diagnostics-app/src/app/views/client-params.tsx index 9a299209..8333e586 100644 --- a/tools/diagnostics-app/src/app/views/client-params.tsx +++ b/tools/diagnostics-app/src/app/views/client-params.tsx @@ -17,6 +17,7 @@ import DeleteIcon from '@mui/icons-material/Delete'; import AddIcon from '@mui/icons-material/Add'; const typeForValue = (value: unknown) => { + //when using typeof arrays are "object" so we have to have this specific case if (Array.isArray(value)) return 'array'; return typeof value; }; @@ -27,12 +28,14 @@ const jsonToObjectArray = (json: Object) => { const type = typeForValue(value); return { key, + // Only arrays and objects need special cases here since JS will take care of the rest. value: type === 'array' || type === 'object' ? JSON.stringify(value) : value, type }; }); }; +// A simple set of mappers for converting a string to the correct value for saving const CONVERTERS = { string: (v: string) => v, number: (v: string) => Number(v), @@ -95,6 +98,7 @@ function ClientParamsPage() { sx={{ margin: '10px' }} onChange={(v: { target: { value: string } }) => changeKey(idx, v.target.value, value, type)} /> + {/* TODO: Potentially add an explanation here about how users should write values for a given piece of text? */} Date: Mon, 11 Nov 2024 11:00:19 +0200 Subject: [PATCH 4/5] Validate client parameters. --- .../src/app/views/client-params.tsx | 76 +++++++++++++------ 1 file changed, 54 insertions(+), 22 deletions(-) diff --git a/tools/diagnostics-app/src/app/views/client-params.tsx b/tools/diagnostics-app/src/app/views/client-params.tsx index 8333e586..43d04453 100644 --- a/tools/diagnostics-app/src/app/views/client-params.tsx +++ b/tools/diagnostics-app/src/app/views/client-params.tsx @@ -22,19 +22,28 @@ const typeForValue = (value: unknown) => { return typeof value; }; -const jsonToObjectArray = (json: Object) => { +const jsonToObjectArray = (json: Object): ParameterEntry[] => { const entrySet = Object.entries(json); return entrySet.map(([key, value]) => { - const type = typeForValue(value); + const type = typeForValue(value) as ParameterType; return { key, // Only arrays and objects need special cases here since JS will take care of the rest. - value: type === 'array' || type === 'object' ? JSON.stringify(value) : value, + value: type === 'array' || type === 'object' ? JSON.stringify(value) : String(value), type }; }); }; +type ParameterType = 'string' | 'number' | 'boolean' | 'array' | 'object'; + +interface ParameterEntry { + key: string; + type: ParameterType; + value: string; + error?: string; +} + // A simple set of mappers for converting a string to the correct value for saving const CONVERTERS = { string: (v: string) => v, @@ -47,41 +56,60 @@ const CONVERTERS = { function ClientParamsPage() { const [params, setParams] = useState(jsonToObjectArray(getParams())); - const convertValueForSave = (t: 'string' | 'number' | 'boolean' | 'array' | 'object', stringValue: string) => - CONVERTERS[t](stringValue); + const convertValueForSave = (t: ParameterType, stringValue: string) => CONVERTERS[t](stringValue); const onSubmit = (e: FormEvent) => { e.preventDefault(); e.stopPropagation(); - const newParams = params.reduce( - (curr: any, item: { key: any; type: 'string' | 'number' | 'boolean' | 'array' | 'object'; value: string }) => ({ - ...curr, - [`${item.key}`]: convertValueForSave(item.type, item.value) - }), - {} - ); - setParamsGlobal(newParams); + try { + const newParams = params.reduce>( + (curr: any, item: { key: string; type: string; value: string }) => ({ + ...curr, + [`${item.key}`]: convertValueForSave(item.type as ParameterType, item.value) + }), + {} + ); + setParamsGlobal(newParams); + } catch (e) {} }; - const replace = (idx: number, val: any) => setParams((a: any[]) => a.map((entity, i) => (i === idx ? val : entity))); + const validate = (val: ParameterEntry) => { + if (val.type == 'object' || val.type == 'array') { + try { + JSON.parse(val.value); + return val; + } catch (e: any) { + return { + ...val, + error: e.message + }; + } + } else { + return val; + } + }; + + const replace = (idx: number, val: ParameterEntry) => { + setParams((a: any[]) => a.map((entity, i) => (i === idx ? validate(val) : entity))); + }; const removeIdx = (idx: number) => setParams((a: any[]) => a.map((entity, i) => i !== idx && entity).filter((entity) => entity !== false)); const addRow = () => { - setParams((a: any[]) => [...a, { key: '', value: '' }]); + setParams((a: any[]) => [...a, { key: '', value: '', type: 'string' }]); }; - const changeValue = (idx: number, value: string, currKey: string, type: string) => { + const changeValue = (idx: number, value: string, currKey: string, type: ParameterType) => { replace(idx, { key: currKey, value, type }); }; - const changeKey = (idx: number, key: string, currValue: unknown, type: string) => { + const changeKey = (idx: number, key: string, currValue: string, type: ParameterType) => { replace(idx, { key, value: currValue, type }); }; - const changeType = (idx: number, key: string, value: unknown, newType: string) => { + const changeType = (idx: number, key: string, value: string, newType: ParameterType) => { replace(idx, { key, value, type: newType }); }; @@ -89,8 +117,8 @@ function ClientParamsPage() { - {params.map(({ key, value, type }: { key: string; value: string; type: string }, idx: number) => ( - + {params.map(({ key, value, type, error }, idx: number) => ( + changeValue(idx, v.target.value, key, type)} /> @@ -111,7 +141,9 @@ function ClientParamsPage() { labelId="demo-simple-select-label" value={type} label="Type" - onChange={(v: { target: { value: string } }) => changeType(idx, key, value, v.target.value)}> + onChange={(v: { target: { value: string } }) => + changeType(idx, key, value, v.target.value as ParameterType) + }> String Number Array @@ -131,7 +163,7 @@ function ClientParamsPage() {
From db84a30000ee64900950a8da5e6760b3fe24e376 Mon Sep 17 00:00:00 2001 From: Ralf Kistner Date: Mon, 11 Nov 2024 11:01:27 +0200 Subject: [PATCH 5/5] Add changeset. --- .changeset/nice-kangaroos-greet.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/nice-kangaroos-greet.md diff --git a/.changeset/nice-kangaroos-greet.md b/.changeset/nice-kangaroos-greet.md new file mode 100644 index 00000000..27430314 --- /dev/null +++ b/.changeset/nice-kangaroos-greet.md @@ -0,0 +1,5 @@ +--- +'@powersync/diagnostics-app': minor +--- + +Support specifying client parameter types