diff --git a/packages/web/src/components/Dialog/ImportDialog.tsx b/packages/web/src/components/Dialog/ImportDialog.tsx index 12889bbc..6f19152b 100644 --- a/packages/web/src/components/Dialog/ImportDialog.tsx +++ b/packages/web/src/components/Dialog/ImportDialog.tsx @@ -100,35 +100,33 @@ export const ImportDialog = ({ open, onOpenChange }: ImportDialogProps) => { }); if ( - deepCompareConfig( + !deepCompareConfig( channels.get(importIndex[index] ?? 0), payload, true, ) ) { - return; + setWorkingChannelConfig(payload); } - - setWorkingChannelConfig(payload); }, ); if (channelSet?.loraConfig && updateConfig) { - const payload = create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "lora", - value: { - ...config.lora, - ...channelSet.loraConfig, - }, - }, - }); - - if (deepCompareConfig(config.lora, payload, true)) { - return; + const payload = { + ...config.lora, + ...channelSet.loraConfig, + }; + + if (!deepCompareConfig(config.lora, payload, true)) { + setWorkingConfig( + create(Protobuf.Config.ConfigSchema, { + payloadVariant: { + case: "lora", + value: payload, + }, + }), + ); } - - setWorkingConfig(payload); } // Reset state after import setImportDialogInput(""); diff --git a/packages/web/src/components/Form/FormPasswordGenerator.tsx b/packages/web/src/components/Form/FormPasswordGenerator.tsx index a56e4d39..0b13d631 100644 --- a/packages/web/src/components/Form/FormPasswordGenerator.tsx +++ b/packages/web/src/components/Form/FormPasswordGenerator.tsx @@ -46,8 +46,8 @@ export function PasswordGenerator({ bits={field.bits} inputChange={(e) => { const value = e.target.value; - controllerField.onChange(value); // ensure RHF receives just the value field.inputChange?.(e); // call any external handler + controllerField.onChange(value); // ensure RHF receives just the value }} selectChange={field.selectChange ?? (() => {})} variant={invalid ? "invalid" : isDirty ? "dirty" : "default"} diff --git a/packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx b/packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx index 20ae370f..8998d515 100644 --- a/packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx +++ b/packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx @@ -14,7 +14,7 @@ import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; import { Protobuf } from "@meshtastic/core"; import { fromByteArray, toByteArray } from "base64-js"; import cryptoRandomString from "crypto-random-string"; -import { useEffect, useMemo, useState } from "react"; +import { useEffect, useMemo, useRef, useState } from "react"; import { type DefaultValues, useForm } from "react-hook-form"; import { useTranslation } from "react-i18next"; @@ -96,9 +96,14 @@ export const Channel = ({ onFormInit, channel }: SettingsPanelProps) => { // Since byteCount is an independent state, we need to use the effective value // from the channel config to ensure the form updates when the setting changes const effectiveByteCount = effectiveConfig.settings?.psk.length ?? 16; + const lastEffectiveRef = useRef(effectiveByteCount); useEffect(() => { - setBytes(effectiveByteCount); - trigger("settings.psk"); + if (effectiveByteCount !== lastEffectiveRef.current) { + lastEffectiveRef.current = effectiveByteCount; + + setBytes(effectiveByteCount); + trigger("settings.psk"); + } }, [effectiveByteCount, trigger]); const onSubmit = (data: ChannelValidation) => { diff --git a/packages/web/src/pages/Config/index.tsx b/packages/web/src/pages/Config/index.tsx index 82ed22a1..4b078d74 100644 --- a/packages/web/src/pages/Config/index.tsx +++ b/packages/web/src/pages/Config/index.tsx @@ -95,29 +95,31 @@ const ConfigPage = () => { ), ); - await connection?.commitEditSettings().then(() => { - if (formMethods) { - formMethods.reset(undefined, { - keepDirty: false, - keepErrors: false, - keepTouched: false, - keepValues: false, - }); + if (workingConfig.length > 0 || workingModuleConfig.length > 0) { + await connection?.commitEditSettings(); + } - // Force RHF to re-validate and emit state - formMethods.trigger(); - } + workingChannelConfig.forEach((newChannel) => addChannel(newChannel)); + workingConfig.forEach((newConfig) => setConfig(newConfig)); + workingModuleConfig.forEach((newModuleConfig) => + setModuleConfig(newModuleConfig), + ); - workingChannelConfig.map((newChannel) => addChannel(newChannel)); - workingConfig.map((newConfig) => setConfig(newConfig)); - workingModuleConfig.map((newModuleConfig) => - setModuleConfig(newModuleConfig), - ); + removeWorkingChannelConfig(); + removeWorkingConfig(); + removeWorkingModuleConfig(); - removeWorkingChannelConfig(); - removeWorkingConfig(); - removeWorkingModuleConfig(); - }); + if (formMethods) { + formMethods.reset(formMethods.getValues(), { + keepDirty: false, + keepErrors: false, + keepTouched: false, + keepValues: false, + }); + + // Force RHF to re-validate and emit state + formMethods.trigger(); + } } catch (_error) { toast({ title: t("toast.configSaveError.title"),