import React, { useState, useEffect } from 'react'; import { Dialog, DialogTitle, DialogContent, DialogActions, Button, TextField, Box, Typography } from '@mui/material'; import { renderParamNameField, renderInfoField, getParamValues } from './ParamEditorUtils'; const NumberParamEditor = ({ open, onClose, nodeId, paramIndex, paramName }) => { const [value, setValue] = useState(null); const [errorMessage, setErrorMessage] = useState(''); const [isValid, setIsValid] = useState(true); // Load initial value useEffect(() => { const localNode = window.localNode; if (!localNode?.nodeParams?.[nodeId] || !localNode.nodeParams[nodeId][paramIndex]) return; const param = localNode.nodeParams[nodeId][paramIndex]; const paramValueField = param.fields.value.msg.unionField; setValue(paramValueField.value); }, [nodeId, paramIndex, paramName]); const handleValueChange = (newValue) => { setValue(newValue); const localNode = window.localNode; const param = localNode?.nodeParams?.[nodeId]?.[paramIndex]; if (!param) { setIsValid(true); setErrorMessage(''); return; } // Skip validation for empty strings or non-numeric values during typing if (newValue === '' || isNaN(parseFloat(newValue))) { setIsValid(false); setErrorMessage('Value must be a number'); return; } const numericValue = parseFloat(newValue); const min = param.fields.min_value.msg && param.fields.min_value.msg.unionField.name !== 'uavcan.protocol.param.Empty' ? param.fields.min_value.msg.unionField.value : null; const max = param.fields.max_value.msg && param.fields.max_value.msg.unionField.name !== 'uavcan.protocol.param.Empty' ? param.fields.max_value.msg.unionField.value : null; // Validate against min/max if they exist if ((min !== null && numericValue < min) || (max !== null && numericValue > max)) { setIsValid(false); setErrorMessage(`Value must be between ${min !== null ? min : '-∞'} and ${max !== null ? max : '∞'}`); } else { setIsValid(true); setErrorMessage(''); } }; const handleSave = () => { const localNode = window.localNode; localNode.setNodeParam(nodeId, paramIndex, parseFloat(value)); onClose(); }; if (value === null) return null; const localNode = window.localNode; const param = localNode?.nodeParams?.[nodeId]?.[paramIndex]; if (!param || !param.fields) return null; const { paramValueField, paramMinValue, paramMaxValue, paramDefaultValue } = getParamValues(param); // Determine step value based on parameter type let step; if (param.fields.value.msg.fields.integer_value !== undefined) { step = 1; } else if (param.fields.value.msg.fields.real_value !== undefined) { step = 0.01; } else { step = 1; } return ( Edit Number Parameter {renderParamNameField(paramName)} handleValueChange(e.target.value)} fullWidth margin="dense" error={!isValid} /> {renderInfoField("Current Value", paramValueField.value)} {paramMinValue !== "" && renderInfoField("Min Value", paramMinValue)} {paramMaxValue !== "" && renderInfoField("Max Value", paramMaxValue)} {paramDefaultValue !== "" && renderInfoField("Default Value", paramDefaultValue)} {errorMessage && ( {errorMessage} )} ); }; export default NumberParamEditor;