Merge branch 'master' into feat/add-error-boundary

This commit is contained in:
Dan Ditomaso
2025-03-01 09:09:57 -05:00
committed by GitHub
75 changed files with 401 additions and 343 deletions
+3 -2
View File
@@ -1,4 +1,5 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import { create } from "@bufbuild/protobuf";
import { Button } from "@components/UI/Button.tsx";
import {
Dialog,
@@ -10,7 +11,7 @@ import {
} from "@components/UI/Dialog.tsx";
import { Input } from "@components/UI/Input.tsx";
import { Label } from "@components/UI/Label.tsx";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { useForm } from "react-hook-form";
export interface User {
@@ -40,7 +41,7 @@ export const DeviceNameDialog = ({
const onSubmit = handleSubmit((data) => {
connection?.setOwner(
new Protobuf.Mesh.User({
create(Protobuf.Mesh.UserSchema, {
...myNode?.user,
...data,
}),
+8 -4
View File
@@ -1,3 +1,4 @@
import { create, fromBinary } from "@bufbuild/protobuf";
import { Button } from "@components/UI/Button.tsx";
import { Checkbox } from "@components/UI/Checkbox.tsx";
import {
@@ -12,7 +13,7 @@ import { Input } from "@components/UI/Input.tsx";
import { Label } from "@components/UI/Label.tsx";
import { Switch } from "@components/UI/Switch.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { toByteArray } from "base64-js";
import { type JSX, useEffect, useState } from "react";
@@ -55,7 +56,10 @@ export const ImportDialog = ({
.replace(/-/g, "+")
.replace(/_/g, "/");
setChannelSet(
Protobuf.AppOnly.ChannelSet.fromBinary(toByteArray(paddedString)),
fromBinary(
Protobuf.AppOnly.ChannelSetSchema,
toByteArray(paddedString),
),
);
setValidUrl(true);
} catch (error) {
@@ -67,7 +71,7 @@ export const ImportDialog = ({
const apply = () => {
channelSet?.settings.map((ch: unknown, index: number) => {
connection?.setChannel(
new Protobuf.Channel.Channel({
create(Protobuf.Channel.ChannelSchema, {
index,
role:
index === 0
@@ -80,7 +84,7 @@ export const ImportDialog = ({
if (channelSet?.loraConfig) {
connection?.setConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "lora",
value: channelSet.loraConfig,
@@ -6,7 +6,7 @@ import {
DialogHeader,
DialogTitle,
} from "@components/UI/Dialog";
import type { Protobuf, Types } from "@meshtastic/js";
import type { Protobuf, Types } from "@meshtastic/core";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import type { JSX } from "react";
@@ -44,7 +44,9 @@ export const LocationResponseDialog = ({
Coordinates:{" "}
<a
className="text-blue-500 dark:text-blue-400"
href={`https://www.openstreetmap.org/?mlat=${location?.data.latitudeI / 1e7}&mlon=${location?.data.longitudeI / 1e7}&layers=N`}
href={`https://www.openstreetmap.org/?mlat=${
location?.data.latitudeI / 1e7
}&mlon=${location?.data.longitudeI / 1e7}&layers=N`}
target="_blank"
rel="noreferrer"
>
+4 -2
View File
@@ -13,7 +13,7 @@ import {
DialogHeader,
DialogTitle,
} from "@components/UI/Dialog";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { DeviceImage } from "../generic/DeviceImage";
import { TimeAgo } from "../generic/TimeAgo";
@@ -87,7 +87,9 @@ export const NodeDetailsDialog = ({
Coordinates:{" "}
<a
className="text-blue-500 dark:text-blue-400"
href={`https://www.openstreetmap.org/?mlat=${device.position.latitudeI / 1e7}&mlon=${device.position.longitudeI / 1e7}&layers=N`}
href={`https://www.openstreetmap.org/?mlat=${
device.position.latitudeI / 1e7
}&mlon=${device.position.longitudeI / 1e7}&layers=N`}
target="_blank"
rel="noreferrer"
>
+1 -1
View File
@@ -7,7 +7,7 @@ import {
DialogHeader,
DialogTitle,
} from "@components/UI/Dialog";
import type { Protobuf } from "@meshtastic/js";
import type { Protobuf } from "@meshtastic/core";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import { TrashIcon } from "lucide-react";
import type { JSX } from "react";
+8 -4
View File
@@ -1,3 +1,4 @@
import { create, toBinary } from "@bufbuild/protobuf";
import { Checkbox } from "@components/UI/Checkbox.tsx";
import {
Dialog,
@@ -9,7 +10,7 @@ import {
} from "@components/UI/Dialog.tsx";
import { Input } from "@components/UI/Input.tsx";
import { Label } from "@components/UI/Label.tsx";
import { Protobuf, type Types } from "@meshtastic/js";
import { Protobuf, type Types } from "@meshtastic/core";
import { fromByteArray } from "base64-js";
import { ClipboardIcon } from "lucide-react";
import { useEffect, useMemo, useState } from "react";
@@ -39,13 +40,16 @@ export const QRDialog = ({
.filter((ch) => selectedChannels.includes(ch.index))
.map((channel) => channel.settings)
.filter((ch): ch is Protobuf.Channel.ChannelSettings => !!ch);
const encoded = new Protobuf.AppOnly.ChannelSet(
new Protobuf.AppOnly.ChannelSet({
const encoded = create(
Protobuf.AppOnly.ChannelSetSchema,
create(Protobuf.AppOnly.ChannelSetSchema, {
loraConfig,
settings: channelsToEncode,
}),
);
const base64 = fromByteArray(encoded.toBinary())
const base64 = fromByteArray(
toBinary(Protobuf.AppOnly.ChannelSetSchema, encoded),
)
.replace(/=/g, "")
.replace(/\+/g, "-")
.replace(/\//g, "_");
@@ -6,7 +6,7 @@ import {
DialogHeader,
DialogTitle,
} from "@components/UI/Dialog";
import type { Protobuf, Types } from "@meshtastic/js";
import type { Protobuf, Types } from "@meshtastic/core";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import type { JSX } from "react";
import { TraceRoute } from "../PageComponents/Messages/TraceRoute";
+21 -18
View File
@@ -100,24 +100,27 @@ export function DynamicForm<T extends FieldValues>({
<Subtle>{fieldGroup.description}</Subtle>
</div>
{fieldGroup.fields.map((field) => (
<FieldWrapper
key={field.label}
label={field.label}
description={field.description}
valid={
field.validationText === undefined ||
field.validationText === ""
}
validationText={field.validationText}
>
<DynamicFormField
field={field}
control={control}
disabled={isDisabled(field.disabledBy, field.disabled)}
/>
</FieldWrapper>
))}
{fieldGroup.fields.map((field) => {
return (
<FieldWrapper
key={field.label}
label={field.label}
fieldName={field.name}
description={field.description}
valid={
field.validationText === undefined ||
field.validationText === ""
}
validationText={field.validationText}
>
<DynamicFormField
field={field}
control={control}
disabled={isDisabled(field.disabledBy, field.disabled)}
/>
</FieldWrapper>
);
})}
</div>
))}
{hasSubmitButton && <Button type="submit">Submit</Button>}
+1
View File
@@ -53,6 +53,7 @@ export function GenericInput<T extends FieldValues>({
}
step={field.properties?.step}
value={field.type === "number" ? Number.parseFloat(value) : value}
id={field.name}
onChange={(e) => {
if (field.inputChange) field.inputChange(e);
onChange(
@@ -11,6 +11,7 @@ import { Controller, type FieldValues } from "react-hook-form";
export interface PasswordGeneratorProps<T> extends BaseFormBuilderProps<T> {
type: "passwordGenerator";
id: string;
hide?: boolean;
bits?: { text: string; value: string; key: string }[];
devicePSKBitCount: number;
@@ -41,6 +42,7 @@ export function PasswordGenerator<T extends FieldValues>({
render={({ field: { value, ...rest } }) => (
<Generator
type={field.hide && !passwordShown ? "password" : "text"}
id={field.id}
action={
field.hide
? {
+1 -1
View File
@@ -50,7 +50,7 @@ export function SelectInput<T extends FieldValues>({
{...remainingProperties}
{...rest}
>
<SelectTrigger>
<SelectTrigger id={field.name}>
<SelectValue />
</SelectTrigger>
<SelectContent>
+1
View File
@@ -33,6 +33,7 @@ export function ToggleInput<T extends FieldValues>({
<Switch
checked={value}
onCheckedChange={onChangeHandler(onChange)}
id={field.name}
disabled={disabled}
{...field.properties}
{...rest}
+3 -1
View File
@@ -2,6 +2,7 @@ import { Label } from "@components/UI/Label.tsx";
export interface FieldWrapperProps {
label: string;
fieldName: string;
description?: string;
disabled?: boolean;
children?: React.ReactNode;
@@ -11,6 +12,7 @@ export interface FieldWrapperProps {
export const FieldWrapper = ({
label,
fieldName,
description,
children,
valid,
@@ -19,7 +21,7 @@ export const FieldWrapper = ({
<div className="pt-6 sm:pt-5">
<fieldset aria-labelledby="label-notifications">
<div className="sm:grid sm:grid-cols-3 sm:items-baseline sm:gap-4">
<Label>{label}</Label>
<Label htmlFor={fieldName}>{label}</Label>
<div className="sm:col-span-2">
<div className="max-w-lg">
<p className="text-sm text-slate-500">{description}</p>
+3 -2
View File
@@ -1,8 +1,9 @@
import type { ChannelValidation } from "@app/validation/channel.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useToast } from "@core/hooks/useToast.ts";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { fromByteArray, toByteArray } from "base64-js";
import cryptoRandomString from "crypto-random-string";
import { useState } from "react";
@@ -27,7 +28,7 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
useState<boolean>(false);
const onSubmit = (data: ChannelValidation) => {
const channel = new Protobuf.Channel.Channel({
const channel = create(Protobuf.Channel.ChannelSchema, {
...data,
settings: {
...data.settings,
@@ -1,8 +1,9 @@
import { useAppStore } from "@app/core/stores/appStore";
import type { BluetoothValidation } from "@app/validation/config/bluetooth.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { useState } from "react";
export const Bluetooth = () => {
@@ -53,7 +54,7 @@ export const Bluetooth = () => {
}
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "bluetooth",
value: data,
@@ -1,14 +1,15 @@
import type { DeviceValidation } from "@app/validation/config/device.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Device = (): JSX.Element => {
const { config, setWorkingConfig } = useDevice();
const onSubmit = (data: DeviceValidation) => {
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "device",
value: data,
@@ -1,14 +1,15 @@
import type { DisplayValidation } from "@app/validation/config/display.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Display = (): JSX.Element => {
const { config, setWorkingConfig } = useDevice();
const onSubmit = (data: DisplayValidation) => {
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "display",
value: data,
@@ -1,14 +1,15 @@
import type { LoRaValidation } from "@app/validation/config/lora.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const LoRa = (): JSX.Element => {
const { config, setWorkingConfig } = useDevice();
const onSubmit = (data: LoRaValidation) => {
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "lora",
value: data,
@@ -1,28 +1,32 @@
import type { NetworkValidation } from "@app/validation/config/network.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import {
convertIntToIpAddress,
convertIpAddressToInt,
} from "@core/utils/ip.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Network = (): JSX.Element => {
const { config, setWorkingConfig } = useDevice();
const onSubmit = (data: NetworkValidation) => {
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "network",
value: {
...data,
ipv4Config: new Protobuf.Config.Config_NetworkConfig_IpV4Config({
ip: convertIpAddressToInt(data.ipv4Config.ip) ?? 0,
gateway: convertIpAddressToInt(data.ipv4Config.gateway) ?? 0,
subnet: convertIpAddressToInt(data.ipv4Config.subnet) ?? 0,
dns: convertIpAddressToInt(data.ipv4Config.dns) ?? 0,
}),
ipv4Config: create(
Protobuf.Config.Config_NetworkConfig_IpV4ConfigSchema,
{
ip: convertIpAddressToInt(data.ipv4Config.ip) ?? 0,
gateway: convertIpAddressToInt(data.ipv4Config.gateway) ?? 0,
subnet: convertIpAddressToInt(data.ipv4Config.subnet) ?? 0,
dns: convertIpAddressToInt(data.ipv4Config.dns) ?? 0,
},
),
},
},
}),
@@ -3,9 +3,10 @@ import {
usePositionFlags,
} from "@app/core/hooks/usePositionFlags";
import type { PositionValidation } from "@app/validation/config/position.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { useCallback } from "react";
export const Position = () => {
@@ -16,7 +17,7 @@ export const Position = () => {
const onSubmit = (data: PositionValidation) => {
return setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "position",
value: { ...data, positionFlags: flagsValue },
@@ -1,14 +1,15 @@
import type { PowerValidation } from "@app/validation/config/power.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Power = (): JSX.Element => {
const { config, setWorkingConfig } = useDevice();
const onSubmit = (data: PowerValidation) => {
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "power",
value: data,
@@ -6,8 +6,9 @@ import {
getX25519PublicKey,
} from "@app/core/utils/x25519";
import type { SecurityValidation } from "@app/validation/config/security.tsx";
import { create } from "@bufbuild/protobuf";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import { fromByteArray, toByteArray } from "base64-js";
import { Eye, EyeOff } from "lucide-react";
import { useReducer } from "react";
@@ -57,7 +58,9 @@ export const Security = () => {
if (input.length % 4 !== 0) {
addError(
fieldName,
`${fieldName === "privateKey" ? "Private" : "Admin"} Key is required to be a 256 bit pre-shared key (PSK)`,
`${
fieldName === "privateKey" ? "Private" : "Admin"
} Key is required to be a 256 bit pre-shared key (PSK)`,
);
return;
}
@@ -71,7 +74,9 @@ export const Security = () => {
console.error(e);
addError(
fieldName,
`Invalid ${fieldName === "privateKey" ? "Private" : "Admin"} Key format`,
`Invalid ${
fieldName === "privateKey" ? "Private" : "Admin"
} Key format`,
);
}
};
@@ -83,7 +88,7 @@ export const Security = () => {
console.log(toByteArray(state.adminKey));
setWorkingConfig(
new Protobuf.Config.Config({
create(Protobuf.Config.ConfigSchema, {
payloadVariant: {
case: "security",
value: {
@@ -164,6 +169,7 @@ export const Security = () => {
fields: [
{
type: "passwordGenerator",
id: "pskInput",
name: "privateKey",
label: "Private Key",
description: "Used to create a shared key with a remote device",
@@ -234,6 +240,7 @@ export const Security = () => {
{
type: "passwordGenerator",
name: "adminKey",
id: "adminKeyInput",
label: "Admin Key",
description:
"The public key authorized to send admin messages to this node",
@@ -241,7 +248,7 @@ export const Security = () => {
? getErrorMessage("adminKey")
: "",
inputChange: adminKeyInputChangeEvent,
selectChange: () => { },
selectChange: () => {},
bits: [{ text: "256 bit", value: "32", key: "bit256" }],
devicePSKBitCount: state.privateKeyBitCount,
hide: !state.adminKeyVisible,
@@ -7,7 +7,8 @@ import { useAppStore } from "@core/stores/appStore.ts";
import { useDeviceStore } from "@core/stores/deviceStore.ts";
import { subscribeAll } from "@core/subscriptions.ts";
import { randId } from "@core/utils/randId.ts";
import { HttpConnection } from "@meshtastic/js";
import { MeshDevice } from "@meshtastic/core";
import { TransportHTTP } from "@meshtastic/transport-http";
import { type JSX, useState } from "react";
import { Controller, useForm } from "react-hook-form";
@@ -36,13 +37,9 @@ export const HTTP = ({ closeDialog }: TabElementProps): JSX.Element => {
const id = randId();
const device = addDevice(id);
const connection = new HttpConnection(id);
// TODO: Promise never resolves
await connection.connect({
address: data.ip,
fetchInterval: 2000,
tls: data.tls,
});
const transport = await TransportHTTP.create(data.ip, data.tls);
const connection = new MeshDevice(transport, id);
connection.configure();
setSelectedDevice(id);
device.addConnection(connection);
@@ -5,7 +5,8 @@ import { useAppStore } from "@core/stores/appStore.ts";
import { useDeviceStore } from "@core/stores/deviceStore.ts";
import { subscribeAll } from "@core/subscriptions.ts";
import { randId } from "@core/utils/randId.ts";
import { SerialConnection } from "@meshtastic/js";
import { MeshDevice } from "@meshtastic/core";
import { TransportWebSerial } from "@meshtastic/transport-web-serial";
import { useCallback, useEffect, useState } from "react";
export const Serial = ({ closeDialog }: TabElementProps): JSX.Element => {
@@ -31,14 +32,9 @@ export const Serial = ({ closeDialog }: TabElementProps): JSX.Element => {
const id = randId();
const device = addDevice(id);
setSelectedDevice(id);
const connection = new SerialConnection(id);
await connection
.connect({
port,
baudRate: undefined,
concurrentLogOutput: true,
})
.catch((e: Error) => console.log(`Unable to Connect: ${e.message}`));
const transport = await TransportWebSerial.createFromPort(port);
const connection = new MeshDevice(transport, id);
connection.configure();
device.addConnection(connection);
subscribeAll(device, connection);
@@ -5,8 +5,8 @@ import { formatQuantity } from "@app/core/utils/string";
import { Avatar } from "@components/UI/Avatar";
import { Mono } from "@components/generic/Mono.tsx";
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
import { Protobuf } from "@meshtastic/js";
import type { Protobuf as ProtobufType } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
import type { Protobuf as ProtobufType } from "@meshtastic/core";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import {
BatteryChargingIcon,
@@ -4,7 +4,7 @@ import {
} from "@app/core/stores/deviceStore.ts";
import { Message } from "@components/PageComponents/Messages/Message.tsx";
import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx";
import type { Types } from "@meshtastic/js";
import type { Types } from "@meshtastic/core";
import { InboxIcon } from "lucide-react";
import { useCallback, useEffect, useRef } from "react";
import type { JSX } from "react";
@@ -11,7 +11,7 @@ import {
} from "@app/core/stores/deviceStore.ts";
import { cn } from "@app/core/utils/cn";
import { Avatar } from "@components/UI/Avatar";
import type { Protobuf } from "@meshtastic/js";
import type { Protobuf } from "@meshtastic/core";
import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react";
import type { LucideIcon } from "lucide-react";
import { useMemo } from "react";
@@ -2,7 +2,7 @@ import { debounce } from "@app/core/utils/debounce";
import { Button } from "@components/UI/Button.tsx";
import { Input } from "@components/UI/Input.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import type { Types } from "@meshtastic/js";
import type { Types } from "@meshtastic/core";
import { SendIcon } from "lucide-react";
import {
type JSX,
@@ -1,5 +1,5 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { Protobuf } from "@meshtastic/js";
import type { Protobuf } from "@meshtastic/core";
import { numberToHexUnpadded } from "@noble/curves/abstract/utils";
import type { JSX } from "react";
@@ -1,14 +1,15 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { AmbientLightingValidation } from "@app/validation/moduleConfig/ambientLighting.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const AmbientLighting = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: AmbientLightingValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "ambientLighting",
value: data,
@@ -1,14 +1,15 @@
import type { AudioValidation } from "@app/validation/moduleConfig/audio.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Audio = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: AudioValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "audio",
value: data,
@@ -1,14 +1,15 @@
import type { CannedMessageValidation } from "@app/validation/moduleConfig/cannedMessage.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const CannedMessage = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: CannedMessageValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "cannedMessage",
value: data,
@@ -1,14 +1,15 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { DetectionSensorValidation } from "@app/validation/moduleConfig/detectionSensor.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const DetectionSensor = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: DetectionSensorValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "detectionSensor",
value: data,
@@ -1,14 +1,15 @@
import type { ExternalNotificationValidation } from "@app/validation/moduleConfig/externalNotification.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const ExternalNotification = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: ExternalNotificationValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "externalNotification",
value: data,
@@ -1,22 +1,23 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { MqttValidation } from "@app/validation/moduleConfig/mqtt.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const MQTT = (): JSX.Element => {
const { config, moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: MqttValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "mqtt",
value: {
...data,
mapReportSettings:
new Protobuf.ModuleConfig.ModuleConfig_MapReportSettings(
data.mapReportSettings,
),
mapReportSettings: create(
Protobuf.ModuleConfig.ModuleConfig_MapReportSettingsSchema,
data.mapReportSettings,
),
},
},
}),
@@ -1,14 +1,15 @@
import { useDevice } from "@app/core/stores/deviceStore.ts";
import type { NeighborInfoValidation } from "@app/validation/moduleConfig/neighborInfo.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const NeighborInfo = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: NeighborInfoValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "neighborInfo",
value: data,
@@ -1,14 +1,15 @@
import type { PaxcounterValidation } from "@app/validation/moduleConfig/paxcounter.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Paxcounter = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: PaxcounterValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "paxcounter",
value: data,
@@ -1,14 +1,15 @@
import type { RangeTestValidation } from "@app/validation/moduleConfig/rangeTest.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const RangeTest = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: RangeTestValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "rangeTest",
value: data,
@@ -1,14 +1,15 @@
import type { SerialValidation } from "@app/validation/moduleConfig/serial.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Serial = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: SerialValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "serial",
value: data,
@@ -1,14 +1,15 @@
import type { StoreForwardValidation } from "@app/validation/moduleConfig/storeForward.ts";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const StoreForward = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: StoreForwardValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "storeForward",
value: data,
@@ -1,14 +1,15 @@
import type { TelemetryValidation } from "@app/validation/moduleConfig/telemetry.tsx";
import { create } from "@bufbuild/protobuf";
import { DynamicForm } from "@components/Form/DynamicForm.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import { Protobuf } from "@meshtastic/js";
import { Protobuf } from "@meshtastic/core";
export const Telemetry = (): JSX.Element => {
const { moduleConfig, setWorkingModuleConfig } = useDevice();
const onSubmit = (data: TelemetryValidation) => {
setWorkingModuleConfig(
new Protobuf.ModuleConfig.ModuleConfig({
create(Protobuf.ModuleConfig.ModuleConfigSchema, {
payloadVariant: {
case: "telemetry",
value: data,
+3 -1
View File
@@ -15,6 +15,7 @@ export interface GeneratorProps extends React.BaseHTMLAttributes<HTMLElement> {
type: "text" | "password";
devicePSKBitCount?: number;
value: string;
id: string;
variant: "default" | "invalid";
actionButtons: {
text: string;
@@ -37,6 +38,7 @@ const Generator = React.forwardRef<HTMLInputElement, GeneratorProps>(
{
type,
devicePSKBitCount,
id = "pskInput",
variant,
value,
actionButtons,
@@ -73,7 +75,7 @@ const Generator = React.forwardRef<HTMLInputElement, GeneratorProps>(
<>
<Input
type={type}
id="pskInput"
id={id}
variant={variant}
value={value}
onChange={inputChange}