From d3003d779c0e7034b912b1d4625310f38746dda1 Mon Sep 17 00:00:00 2001 From: Paul Farault Date: Fri, 3 Mar 2023 10:45:50 +0100 Subject: [PATCH] feat: share state between raw and view mode Add react-hook-form to optimize state. Sync code editor in read mode (import values from view). Persit user settings accross pages (raw mode, show unused tabs). Fixes #96 Fixes #164 TODO: sync code editor in write mode. --- src/components/Services/VariablesDisplay.tsx | 225 ++++++++++++------- 1 file changed, 141 insertions(+), 84 deletions(-) diff --git a/src/components/Services/VariablesDisplay.tsx b/src/components/Services/VariablesDisplay.tsx index b981470..dc6fa7f 100644 --- a/src/components/Services/VariablesDisplay.tsx +++ b/src/components/Services/VariablesDisplay.tsx @@ -1,33 +1,122 @@ import { useState } from 'react' +import { + useForm, + FormProvider, + useFormContext, + useFormState, +} from 'react-hook-form' import Editor from '@monaco-editor/react' import { Bars3CenterLeftIcon, EyeIcon } from '@heroicons/react/24/solid' import { Disclosure, Sidebar } from 'src/components/Layout' import { Button, IconButon } from 'src/components/commons' -import { useAppDispatch } from 'src/store' -import { setProperty } from 'src/features/userInput' import { classNames } from 'src/utils' import { useParamsContext } from './ParamsContext' import { usePutServiceConfig } from 'src/hooks' +import { ComponentsNav } from './ComponentsNav' +import { useAppDispatch } from 'src/store' +import { + clearUserInput, + setComponent, + setRawMode, + setServiceVariables, +} from 'src/features/userInput' +import { useSelectUserInput } from 'src/features/userInput/hooks' export function VariablesDisplay({ variables }: { variables: Object }) { - const [isRawMode, setIsRawMode] = useState(false) - const isVariableEmpty = !Object.entries(variables).length + const methods = useForm({ defaultValues: variables }) + + return ( + +
+ + ) +} + +function Form({ variables }: { variables: Object }) { + const { currentServiceId, currentComponentId } = useParamsContext() + const dispatch = useAppDispatch() + const { getValues, control } = useFormContext() + const { dirtyFields } = useFormState({ control }) + + function saveVariables() { + const dirtyValues = getDirtyValues(dirtyFields, getValues) + if (currentServiceId && currentComponentId) { + dispatch( + setComponent({ + componentId: currentComponentId, + variables: dirtyValues, + }) + ) + } + if (currentServiceId && !currentComponentId) { + dispatch(setServiceVariables(dirtyValues)) + } + } + return ( + <> + + {/* key let React re-render the component when the currentServiceId or currentComponentId changes */} + + + ) +} + +function Variables({ + variables, + saveVariables, +}: { + variables: Object + saveVariables: () => void +}) { + const { sendVariables } = usePutServiceConfig() + const dispatch = useAppDispatch() + const { + settings: { showRawMode }, + } = useSelectUserInput() + const [message, setMessage] = useState('') + const methods = useFormContext() + + function handleSubmit(data: Object) { + sendVariables(message) + setMessage('') + dispatch(clearUserInput()) + } + + const isVariableEmpty = !Object.entries(variables).length if (isVariableEmpty) return return ( <> - - {isRawMode ? ( - - ) : ( - - )} - + + + {showRawMode ? ( + + ) : ( + + )} + + ) } +function getDirtyValues(dirtyFields: Object, getValues: (key: string) => any) { + const dirtyValues = {} + Object.keys(dirtyFields).forEach((key) => { + dirtyValues[key] = getValues(key) + }) + return dirtyValues +} + function NoVariableMessage() { const { currentServiceId, currentComponentId } = useParamsContext() return ( @@ -37,38 +126,36 @@ function NoVariableMessage() { ) } -function Toolbar({ - isRawMode, - setIsRawMode, -}: { - isRawMode: boolean - setIsRawMode: (isRaw: boolean) => void -}) { +function Toolbar({ saveVariables }: { saveVariables: () => void }) { return (
- +
) } -function RawViewButton({ - isRaw, - setIsRaw, -}: { - isRaw: boolean - setIsRaw: React.Dispatch> -}) { +function RawViewButton({ saveVariables }: { saveVariables: () => void }) { + const dispatch = useAppDispatch() + const { + settings: { showRawMode }, + } = useSelectUserInput() + + function handleSetRawMode(rawMode: boolean) { + saveVariables() + dispatch(setRawMode(rawMode)) + } + return (
setIsRaw(true)} - isActive={isRaw} + onClick={() => handleSetRawMode(true)} + isActive={showRawMode} icon={Bars3CenterLeftIcon} text="Raw" /> setIsRaw(false)} - isActive={!isRaw} + onClick={() => handleSetRawMode(false)} + isActive={!showRawMode} className="-ml-px border-l-gray-400 border-l" icon={EyeIcon} text="View" @@ -92,12 +179,12 @@ function ViewMode({ variables }: { variables: Object }) { const { primitiveVariables, objectVariables: dictionaries } = splitObjectVariables(variables) return ( -
+
{dictionaries.map((dict) => ( ))} - +
) } @@ -123,7 +210,7 @@ function splitObjectVariables(variables: Object) { function Dictionary({ dict }: { dict: [string, Object] }) { const [dictId, dictVariables] = dict return ( - + } if (typeof value === 'boolean') { - return + return } if (typeof value === 'object') { if (Array.isArray(value)) { @@ -219,28 +306,16 @@ function BooleanField({ property: string value: boolean }) { - const { currentServiceId, currentComponentId } = useParamsContext() - const dispatch = useAppDispatch() + const { register } = useFormContext() - function handleChecked(event: React.ChangeEvent) { - const newValue = event.target.checked - dispatch( - setProperty({ - serviceId: currentServiceId, - componentId: currentComponentId, - property, - value: newValue, - }) - ) - } return (
@@ -255,61 +330,43 @@ function StringNumberField({ property: string value: string | number }) { - const { currentServiceId, currentComponentId } = useParamsContext() - const dispatch = useAppDispatch() - const [error, setError] = useState(false) - - function handleChange(event: React.ChangeEvent) { - setError(false) - try { - const newValue = JSON.parse(event.target.value) - dispatch( - setProperty({ - serviceId: currentServiceId, - componentId: currentComponentId, - property, - value: newValue, - }) - ) - } catch (err) { - setError(true) - } - } + const { register } = useFormContext() + //TODO: handle errors + let error return (
) } -function ValidateBar() { - const { sendVariables } = usePutServiceConfig() - const [validateMessage, setValidateMessage] = useState('') - - function handleSubmit(event: React.MouseEvent) { - event.preventDefault() - sendVariables(validateMessage) - setValidateMessage('') - } - +function ValidateBar({ + onValidate, + message, + setMessage, +}: { + onValidate: () => void + message: string + setMessage: (message: string) => void +}) { return (
setValidateMessage(e.target.value)} + value={message} + onChange={(e) => setMessage(e.target.value)} placeholder="Commit message" /> -