WIP updates

This commit is contained in:
Sacha Weatherstone
2022-11-27 22:50:46 +10:00
parent a9561fe622
commit e457cef3da
79 changed files with 2100 additions and 1284 deletions

View File

@@ -22,10 +22,10 @@ export const Bluetooth = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
control,
reset,
reset
} = useForm<BluetoothValidation>({
defaultValues: config.bluetooth,
resolver: classValidatorResolver(BluetoothValidation),
resolver: classValidatorResolver(BluetoothValidation)
});
useEffect(() => {
@@ -35,22 +35,22 @@ export const Bluetooth = (): JSX.Element => {
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection.setConfig(
{
connection.setConfig({
config: {
payloadVariant: {
oneofKind: "bluetooth",
bluetooth: data,
},
bluetooth: data
}
},
async () => {
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved Bluetooth Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -59,7 +59,7 @@ export const Bluetooth = (): JSX.Element => {
const pairingMode = useWatch({
control,
name: "mode",
defaultValue: Protobuf.Config_BluetoothConfig_PairingMode.RANDOM_PIN,
defaultValue: Protobuf.Config_BluetoothConfig_PairingMode.RANDOM_PIN
});
return (
@@ -98,7 +98,7 @@ export const Bluetooth = (): JSX.Element => {
description="Pin to use when pairing"
type="number"
{...register("fixedPin", {
valueAsNumber: true,
valueAsNumber: true
})}
/>
</Form>

View File

@@ -4,6 +4,7 @@ import { useEffect } from "react";
import { Controller, useForm } from "react-hook-form";
import { toast } from "react-hot-toast";
import { Input } from "@app/components/form/Input.js";
import { Select } from "@app/components/form/Select.js";
import { Toggle } from "@app/components/form/Toggle.js";
import { DeviceValidation } from "@app/validation/config/device.js";
@@ -20,10 +21,10 @@ export const Device = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
control,
reset,
reset
} = useForm<DeviceValidation>({
defaultValues: config.device,
resolver: classValidatorResolver(DeviceValidation),
resolver: classValidatorResolver(DeviceValidation)
});
useEffect(() => {
@@ -33,22 +34,22 @@ export const Device = (): JSX.Element => {
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection.setConfig(
{
connection.setConfig({
config: {
payloadVariant: {
oneofKind: "device",
device: data,
},
device: data
}
},
async () => {
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved Device Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -93,6 +94,20 @@ export const Device = (): JSX.Element => {
/>
)}
/>
<Input
label="Button Pin"
description="Button pin override"
type="number"
error={errors.buttonGpio?.message}
{...register("buttonGpio", { valueAsNumber: true })}
/>
<Input
label="Buzzer Pin"
description="Buzzer pin override"
type="number"
error={errors.buzzerGpio?.message}
{...register("buzzerGpio", { valueAsNumber: true })}
/>
</Form>
);
};

View File

@@ -21,10 +21,10 @@ export const Display = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
reset,
control,
control
} = useForm<Protobuf.Config_DisplayConfig>({
defaultValues: config.display,
resolver: classValidatorResolver(DisplayValidation),
resolver: classValidatorResolver(DisplayValidation)
});
useEffect(() => {
@@ -34,22 +34,22 @@ export const Display = (): JSX.Element => {
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection.setConfig(
{
connection.setConfig({
config: {
payloadVariant: {
oneofKind: "display",
display: data,
},
display: data
}
},
async () => {
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved Display Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -115,6 +115,13 @@ export const Display = (): JSX.Element => {
>
{renderOptions(Protobuf.Config_DisplayConfig_DisplayUnits)}
</Select>
<Select
label="OLED Type"
description="Type of OLED screen attached to the device"
{...register("oled", { valueAsNumber: true })}
>
{renderOptions(Protobuf.Config_DisplayConfig_OledType)}
</Select>
</Form>
);
};

View File

@@ -23,16 +23,16 @@ export const LoRa = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
control,
reset,
reset
} = useForm<LoRaValidation>({
defaultValues: config.lora,
resolver: classValidatorResolver(LoRaValidation),
resolver: classValidatorResolver(LoRaValidation)
});
const usePreset = useWatch({
control,
name: "usePreset",
defaultValue: true,
defaultValue: true
});
useEffect(() => {
@@ -42,22 +42,22 @@ export const LoRa = (): JSX.Element => {
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection.setConfig(
{
connection.setConfig({
config: {
payloadVariant: {
oneofKind: "lora",
lora: data,
},
lora: data
}
},
async () => {
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved LoRa Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -99,7 +99,7 @@ export const LoRa = (): JSX.Element => {
suffix="MHz"
error={errors.bandwidth?.message}
{...register("bandwidth", {
valueAsNumber: true,
valueAsNumber: true
})}
disabled={usePreset}
/>
@@ -110,7 +110,7 @@ export const LoRa = (): JSX.Element => {
suffix="CPS"
error={errors.spreadFactor?.message}
{...register("spreadFactor", {
valueAsNumber: true,
valueAsNumber: true
})}
disabled={usePreset}
/>
@@ -120,7 +120,7 @@ export const LoRa = (): JSX.Element => {
type="number"
error={errors.codingRate?.message}
{...register("codingRate", {
valueAsNumber: true,
valueAsNumber: true
})}
disabled={usePreset}
/>

View File

@@ -6,12 +6,14 @@ import { toast } from "react-hot-toast";
import { FormSection } from "@app/components/form/FormSection.js";
import { Input } from "@app/components/form/Input.js";
import { IPAddress } from "@app/components/form/IPAddress.js";
import { Select } from "@app/components/form/Select.js";
import { Toggle } from "@app/components/form/Toggle.js";
import { renderOptions } from "@app/core/utils/selectEnumOptions.js";
import { NetworkValidation } from "@app/validation/config/network.js";
import { Form } from "@components/form/Form";
import { useDevice } from "@core/providers/useDevice.js";
import { ErrorMessage } from "@hookform/error-message";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs";
@@ -22,22 +24,22 @@ export const Network = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
control,
reset,
reset
} = useForm<NetworkValidation>({
defaultValues: config.network,
resolver: classValidatorResolver(NetworkValidation),
resolver: classValidatorResolver(NetworkValidation)
});
const wifiEnabled = useWatch({
control,
name: "wifiEnabled",
defaultValue: false,
defaultValue: false
});
const ethEnabled = useWatch({
control,
name: "ethEnabled",
defaultValue: false,
defaultValue: false
});
useEffect(() => {
@@ -45,24 +47,32 @@ export const Network = (): JSX.Element => {
}, [reset, config.network]);
const onSubmit = handleSubmit((data) => {
console.log(data);
if (connection) {
const tmp = Protobuf.Config_NetworkConfig.create({
ethEnabled: true,
ethMode: Protobuf.Config_NetworkConfig_EthMode.DHCP
});
void toast.promise(
connection.setConfig(
{
payloadVariant: {
oneofKind: "network",
network: data,
connection
.setConfig({
config: {
payloadVariant: {
oneofKind: "network",
network: tmp
}
},
},
async () => {
reset({ ...data });
await Promise.resolve();
}
),
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
})
.catch((e) => console.log(e)),
{
loading: "Saving...",
success: "Saved Network Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -76,6 +86,19 @@ export const Network = (): JSX.Element => {
dirty={isDirty}
onSubmit={onSubmit}
>
<ErrorMessage errors={errors} name="wifiEnabled" />
<ErrorMessage errors={errors} name="wifiMode" />
<ErrorMessage errors={errors} name="wifiSsid" />
<ErrorMessage errors={errors} name="wifiPsk" />
<ErrorMessage errors={errors} name="ntpServer" />
<ErrorMessage errors={errors} name="ethEnabled" />
<ErrorMessage errors={errors} name="ethMode" />
<ErrorMessage errors={errors} name="ethConfig" />
<ErrorMessage errors={errors} name="ip" />
<ErrorMessage errors={errors} name="gateway" />
<ErrorMessage errors={errors} name="subnet" />
<ErrorMessage errors={errors} name="dns" />
<FormSection title="WiFi Config">
<Controller
name="wifiEnabled"
@@ -83,26 +106,18 @@ export const Network = (): JSX.Element => {
render={({ field: { value, ...rest } }) => (
<Toggle
label="WiFi Enabled"
description="Enable or disbale the WiFi radio"
description="Enable or disable the WiFi radio"
checked={value}
{...rest}
/>
)}
/>
<Select
label="WiFi Mode"
description="How the WiFi radio should be used"
disabled={!wifiEnabled}
{...register("wifiMode", { valueAsNumber: true })}
>
{renderOptions(Protobuf.Config_NetworkConfig_WiFiMode)}
</Select>
<Input
label="SSID"
description="Network name"
error={errors.wifiSsid?.message}
disabled={!wifiEnabled}
{...register("wifiSsid")}
{...register("wifiSsid", { disabled: !wifiEnabled })}
/>
<Input
label="PSK"
@@ -110,7 +125,7 @@ export const Network = (): JSX.Element => {
description="Network password"
error={errors.wifiPsk?.message}
disabled={!wifiEnabled}
{...register("wifiPsk")}
{...register("wifiPsk", { disabled: !wifiEnabled })}
/>
</FormSection>
<FormSection title="Ethernet Config">
@@ -130,35 +145,43 @@ export const Network = (): JSX.Element => {
label="Ethernet Mode"
description="Address assignment selection"
disabled={!ethEnabled}
{...register("ethMode", { valueAsNumber: true })}
{...register("ethMode", {
valueAsNumber: true,
disabled: !ethEnabled
})}
>
{renderOptions(Protobuf.Config_NetworkConfig_EthMode)}
</Select>
</FormSection>
<FormSection title="IP Config">
<IPAddress label="IP" description="IP Address" />
<Input
label="IP"
type="number"
description="IP Address"
error={errors.ethConfig?.ip?.message}
{...register("ethConfig.ip")}
error={errors.ipv4Config?.ip?.message}
{...register("ipv4Config.ip", { valueAsNumber: true })}
/>
<Input
label="Gateway"
type="number"
description="Default Gateway"
error={errors.ethConfig?.gateway?.message}
{...register("ethConfig.gateway")}
error={errors.ipv4Config?.gateway?.message}
{...register("ipv4Config.gateway", { valueAsNumber: true })}
/>
<Input
label="Subnet"
type="number"
description="Subnet Mask"
error={errors.ethConfig?.subnet?.message}
{...register("ethConfig.subnet")}
error={errors.ipv4Config?.subnet?.message}
{...register("ipv4Config.subnet", { valueAsNumber: true })}
/>
<Input
label="DNS"
type="number"
description="DNS Server"
error={errors.ethConfig?.dns?.message}
{...register("ethConfig.dns")}
error={errors.ipv4Config?.dns?.message}
{...register("ipv4Config.dns", { valueAsNumber: true })}
/>
</FormSection>
<Input

View File

@@ -4,6 +4,7 @@ import { useEffect } from "react";
import { Controller, useForm, useWatch } from "react-hook-form";
import { toast } from "react-hot-toast";
import { BitwiseSelect } from "@app/components/form/BitwiseSelect.js";
import { FormSection } from "@app/components/form/FormSection.js";
import { Input } from "@app/components/form/Input.js";
import { Toggle } from "@app/components/form/Toggle.js";
@@ -23,21 +24,21 @@ export const Position = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
reset,
control,
control
} = useForm<PositionValidation>({
defaultValues: {
fixedAlt: myNode?.data.position?.altitude,
fixedLat: (myNode?.data.position?.latitudeI ?? 0) / 1e7,
fixedLng: (myNode?.data.position?.longitudeI ?? 0) / 1e7,
...config.position,
...config.position
},
resolver: classValidatorResolver(PositionValidation),
resolver: classValidatorResolver(PositionValidation)
});
const fixedPositionEnabled = useWatch({
control,
name: "fixedPosition",
defaultValue: false,
defaultValue: false
});
useEffect(() => {
@@ -45,7 +46,7 @@ export const Position = (): JSX.Element => {
fixedAlt: myNode?.data.position?.altitude,
fixedLat: (myNode?.data.position?.latitudeI ?? 0) / 1e7,
fixedLng: (myNode?.data.position?.longitudeI ?? 0) / 1e7,
...config.position,
...config.position
});
}, [reset, config.position, myNode?.data.position]);
@@ -59,49 +60,41 @@ export const Position = (): JSX.Element => {
if (connection) {
void toast.promise(
connection.sendPacket(
Protobuf.Position.toBinary(
Protobuf.Position.create({
altitude: fixedAlt,
latitudeI: fixedLat * 1e7,
longitudeI: fixedLng * 1e7,
})
),
Protobuf.PortNum.POSITION_APP,
undefined,
true,
undefined,
true,
false,
async () => {
connection.setPosition({
position: Protobuf.Position.create({
altitude: fixedAlt,
latitudeI: fixedLat * 1e7,
longitudeI: fixedLng * 1e7
}),
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved Channel",
error: "No response received",
error: "No response received"
}
);
if (configHasChanged) {
void toast.promise(
connection.setConfig(
{
connection.setConfig({
config: {
payloadVariant: {
oneofKind: "position",
position: rest,
},
position: rest
}
},
async () => {
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved Position Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -201,94 +194,65 @@ export const Position = (): JSX.Element => {
error={errors.gpsAttemptTime?.message}
{...register("gpsAttemptTime", { valueAsNumber: true })}
/>
{/* <Controller
<Controller
name="positionFlags"
control={control}
render={({ field, fieldState }): JSX.Element => {
const { value, onChange, ...rest } = field;
const { error } = fieldState;
const options = Object.entries(
Protobuf.Config_PositionConfig_PositionFlags
)
.filter((value) => typeof value[1] !== "number")
.filter(
(value) =>
parseInt(value[0]) !==
Protobuf.Config_PositionConfig_PositionFlags.UNSET
)
.map((value) => {
return {
value: parseInt(value[0]),
label: value[1].toString().replace("POS_", "").toLowerCase(),
};
});
// const options = Object.entries(
// Protobuf.Config_PositionConfig_PositionFlags
// )
// .filter((value) => typeof value[1] !== "number")
// .filter(
// (value) =>
// parseInt(value[0]) !==
// Protobuf.Config_PositionConfig_PositionFlags.UNSET
// )
// .map((value) => {
// return {
// value: parseInt(value[0]),
// label: value[1].toString().replace("POS_", "").toLowerCase(),
// };
// });
const selected = bitwiseDecode(
value,
Protobuf.Config_PositionConfig_PositionFlags
).map((flag) =>
Protobuf.Config_PositionConfig_PositionFlags[flag]
.replace("POS_", "")
.toLowerCase()
);
// const selected = bitwiseDecode(
// value,
// Protobuf.Config_PositionConfig_PositionFlags
// ).map((flag) =>
// Protobuf.Config_PositionConfig_PositionFlags[flag]
// .replace("POS_", "")
// .toLowerCase()
// );
// onChange={(e: { value: number; label: string }[]): void =>
// onChange(bitwiseEncode(e.map((v) => v.value)))
// }
return (
<FormField
<BitwiseSelect
label="Position Flags"
description="Description"
isInvalid={!!errors.positionFlags?.message}
validationMessage={errors.positionFlags?.message}
>
<SelectMenu
isMultiSelect
title="Select multiple names"
options={options}
selected={selected}
// onSelect={(item) => {
// const selected = [...selectedItemsState, item.value]
// const selectedItems = selected
// const selectedItemsLength = selectedItems.length
// let selectedNames = ''
// if (selectedItemsLength === 0) {
// selectedNames = ''
// } else if (selectedItemsLength === 1) {
// selectedNames = selectedItems.toString()
// } else if (selectedItemsLength > 1) {
// selectedNames = selectedItemsLength.toString() + ' selected...'
// }
// setSelectedItems(selectedItems)
// setSelectedItemNames(selectedNames)
// }}
// onDeselect={(item) => {
// const deselectedItemIndex = selectedItemsState.indexOf(item.value)
// const selectedItems = selectedItemsState.filter((_item, i) => i !== deselectedItemIndex)
// const selectedItemsLength = selectedItems.length
// let selectedNames = ''
// if (selectedItemsLength === 0) {
// selectedNames = ''
// } else if (selectedItemsLength === 1) {
// selectedNames = selectedItems.toString()
// } else if (selectedItemsLength > 1) {
// selectedNames = selectedItemsLength.toString() + ' selected...'
// }
// setSelectedItems(selectedItems)
// setSelectedItemNames(selectedNames)
// }}
>
<Button>
{selected.map(
(item, index) =>
`${item}${index !== selected.length - 1 ? ", " : ""}`
)}
</Button>
</SelectMenu>
</FormField>
error={error?.message}
selected={value}
decodeEnun={Protobuf.Config_PositionConfig_PositionFlags}
onChange={onChange}
/>
);
}}
/> */}
/>
<Input
label="RX Pin"
description="GPS Module RX pin override"
type="number"
error={errors.rxGpio?.message}
{...register("rxGpio", { valueAsNumber: true })}
/>
<Input
label="TX Pin"
description="GPS Module TX pin override"
type="number"
error={errors.txGpio?.message}
{...register("txGpio", { valueAsNumber: true })}
/>
</Form>
);
};

View File

@@ -19,10 +19,10 @@ export const Power = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
reset,
control,
control
} = useForm<PowerValidation>({
defaultValues: config.power,
resolver: classValidatorResolver(PowerValidation),
resolver: classValidatorResolver(PowerValidation)
});
useEffect(() => {
@@ -32,22 +32,22 @@ export const Power = (): JSX.Element => {
const onSubmit = handleSubmit((data) => {
if (connection) {
void toast.promise(
connection.setConfig(
{
connection.setConfig({
config: {
payloadVariant: {
oneofKind: "power",
power: data,
},
power: data
}
},
async () => {
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
),
}),
{
loading: "Saving...",
success: "Saved Power Config, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}

View File

@@ -25,31 +25,34 @@ export const User = (): JSX.Element => {
handleSubmit,
formState: { errors, isDirty },
reset,
control,
control
} = useForm<UserValidation>({
defaultValues: myNode?.data.user,
resolver: classValidatorResolver(UserValidation),
resolver: classValidatorResolver(UserValidation)
});
useEffect(() => {
reset({
longName: myNode?.data.user?.longName,
shortName: myNode?.data.user?.shortName,
isLicensed: myNode?.data.user?.isLicensed,
isLicensed: myNode?.data.user?.isLicensed
});
}, [reset, myNode]);
const onSubmit = handleSubmit((data) => {
if (connection && myNode?.data.user) {
void toast.promise(
connection.setOwner({ ...myNode.data.user, ...data }, async () => {
reset({ ...data });
await Promise.resolve();
connection.setOwner({
owner: { ...myNode.data.user, ...data },
callback: async () => {
reset({ ...data });
await Promise.resolve();
}
}),
{
loading: "Saving...",
success: "Saved User, Restarting Node",
error: "No response received",
error: "No response received"
}
);
}
@@ -63,7 +66,7 @@ export const User = (): JSX.Element => {
reset({
longName: myNode?.data.user?.longName,
shortName: myNode?.data.user?.shortName,
isLicensed: myNode?.data.user?.isLicensed,
isLicensed: myNode?.data.user?.isLicensed
});
}}
dirty={isDirty}