Browse Source

Minor fixes, start channel editor migration

pull/101/head
Sacha Weatherstone 3 years ago
parent
commit
d79a6965c0
No known key found for this signature in database GPG Key ID: 7AB2D7E206124B31
  1. 4
      src/components/Dialog/QRDialog.tsx
  2. 425
      src/components/PageComponents/Channel.tsx
  3. 8
      src/pages/Config/index.tsx
  4. 2
      src/pages/Map.tsx
  5. 15
      src/validation/channelSettings.ts

4
src/components/Dialog/QRDialog.tsx

@ -63,7 +63,7 @@ export const QRDialog = ({
<div className="flex gap-3 px-4 py-5 sm:p-6"> <div className="flex gap-3 px-4 py-5 sm:p-6">
<div className="flex w-40 flex-col gap-1"> <div className="flex w-40 flex-col gap-1">
{channels.map((channel) => ( {channels.map((channel) => (
<> <div key={channel.index}>
<Label> <Label>
{channel.settings?.name.length {channel.settings?.name.length
? channel.settings.name ? channel.settings.name
@ -87,7 +87,7 @@ export const QRDialog = ({
} }
}} }}
/> />
</> </div>
))} ))}
</div> </div>
<QRCode value={QRCodeURL} size={200} qrStyle="dots" /> <QRCode value={QRCodeURL} size={200} qrStyle="dots" />

425
src/components/PageComponents/Channel.tsx

@ -1,14 +1,9 @@
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import { fromByteArray, toByteArray } from "base64-js"; import { fromByteArray, toByteArray } from "base64-js";
import { Controller, useForm } from "react-hook-form"; import type { ChannelSettingsValidation } from "@app/validation/channelSettings.js";
import { ChannelSettingsValidation } from "@app/validation/channelSettings.js";
import { Input } from "@components/UI/Input.js";
import { Switch } from "@components/UI/Switch.js";
import { useDevice } from "@core/stores/deviceStore.js"; import { useDevice } from "@core/stores/deviceStore.js";
import { RefreshCwIcon, EyeIcon, EyeOffIcon } from "lucide-react";
import { classValidatorResolver } from "@hookform/resolvers/class-validator";
import { Protobuf } from "@meshtastic/meshtasticjs"; import { Protobuf } from "@meshtastic/meshtasticjs";
import { Label } from "@radix-ui/react-label"; import { DynamicForm } from "../Form/DynamicForm.js";
export interface SettingsPanelProps { export interface SettingsPanelProps {
channel: Protobuf.Channel; channel: Protobuf.Channel;
@ -19,168 +14,268 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
const [keySize, setKeySize] = useState<128 | 256>(256); const [keySize, setKeySize] = useState<128 | 256>(256);
const [pskHidden, setPskHidden] = useState(true); const [pskHidden, setPskHidden] = useState(true);
const { // const {
register, // register,
handleSubmit, // handleSubmit,
formState: { errors, isDirty }, // formState: { errors, isDirty },
reset, // reset,
control, // control,
setValue // setValue
} = useForm<ChannelSettingsValidation>({ // } = useForm<ChannelSettingsValidation>({
defaultValues: { // defaultValues: {
enabled: [ // enabled: [
Protobuf.Channel_Role.SECONDARY, // Protobuf.Channel_Role.SECONDARY,
Protobuf.Channel_Role.PRIMARY // Protobuf.Channel_Role.PRIMARY
].find((role) => role === channel?.role) // ].find((role) => role === channel?.role)
? true // ? true
: false, // : false,
...channel?.settings, // ...channel?.settings,
psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0)) // psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0))
}, // },
resolver: classValidatorResolver(ChannelSettingsValidation) // resolver: classValidatorResolver(ChannelSettingsValidation)
}); // });
useEffect(() => { // useEffect(() => {
reset({ // reset({
enabled: [ // enabled: [
Protobuf.Channel_Role.SECONDARY, // Protobuf.Channel_Role.SECONDARY,
Protobuf.Channel_Role.PRIMARY // Protobuf.Channel_Role.PRIMARY
].find((role) => role === channel?.role) // ].find((role) => role === channel?.role)
? true // ? true
: false, // : false,
...channel?.settings, // ...channel?.settings,
psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0)) // psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0))
}); // });
}, [channel, reset]); // }, [channel, reset]);
const onSubmit = handleSubmit((data) => { // const onSubmit = handleSubmit((data) => {
connection // connection
?.setChannel( // ?.setChannel(
new Protobuf.Channel({ // new Protobuf.Channel({
role: // role:
channel?.role === Protobuf.Channel_Role.PRIMARY // channel?.role === Protobuf.Channel_Role.PRIMARY
? Protobuf.Channel_Role.PRIMARY // ? Protobuf.Channel_Role.PRIMARY
: data.enabled // : data.enabled
? Protobuf.Channel_Role.SECONDARY // ? Protobuf.Channel_Role.SECONDARY
: Protobuf.Channel_Role.DISABLED, // : Protobuf.Channel_Role.DISABLED,
index: channel?.index, // index: channel?.index,
settings: { // settings: {
...data, // ...data,
psk: toByteArray(data.psk ?? "") // psk: toByteArray(data.psk ?? "")
} // }
}) // })
) // )
.then(() => // .then(() =>
addChannel({ // addChannel({
config: new Protobuf.Channel({ // config: new Protobuf.Channel({
index: channel.index, // index: channel.index,
role: channel.role, // role: channel.role,
settings: { // settings: {
...data, // ...data,
psk: toByteArray(data.psk ?? "") // psk: toByteArray(data.psk ?? "")
} // }
}), // }),
lastInterraction: new Date(), // lastInterraction: new Date(),
messages: [] // messages: []
}) // })
); // );
}); // });
const onSubmit = (data: ChannelSettingsValidation) => {
console.log(data);
};
return ( return (
<div className="p-3"> // <div className="p-3">
<form onSubmit={onSubmit}> // <form onSubmit={onSubmit}>
{channel?.index !== 0 && ( // {channel?.index !== 0 && (
<> // <>
<Controller // <Controller
name="enabled" // name="enabled"
control={control} // control={control}
render={({ field: { value, ...rest } }) => ( // render={({ field: { value, ...rest } }) => (
<> // <>
<Label>Enabled</Label> // <Label>Enabled</Label>
<Switch // <Switch
// label="Enabled" // // label="Enabled"
// description="Description" // // description="Description"
checked={value} // checked={value}
{...rest} // {...rest}
/> // />
</> // </>
)} // )}
/> // />
<Label>Name</Label> // <Label>Name</Label>
<Input // <Input
// description="Max transmit power in dBm" // // description="Max transmit power in dBm"
// error={errors.name?.message} // // error={errors.name?.message}
{...register("name")} // {...register("name")}
/> // />
</> // </>
)} // )}
{/* <Select // {/* <Select
label="Key Size" // label="Key Size"
description="Desired size of generated key." // description="Desired size of generated key."
value={keySize} // value={keySize}
onChange={(e): void => { // onChange={(e): void => {
setKeySize(parseInt(e.target.value) as 128 | 256); // setKeySize(parseInt(e.target.value) as 128 | 256);
}} // }}
action={{ // action={{
icon: <RefreshCwIcon size={16} />, // icon: <RefreshCwIcon size={16} />,
action: () => { // action: () => {
const key = new Uint8Array(keySize / 8); // const key = new Uint8Array(keySize / 8);
crypto.getRandomValues(key); // crypto.getRandomValues(key);
setValue("psk", fromByteArray(key), { // setValue("psk", fromByteArray(key), {
shouldDirty: true // shouldDirty: true
}); // });
} // }
}} // }}
> // >
<option value={128}>128 Bit</option> // <option value={128}>128 Bit</option>
<option value={256}>256 Bit</option> // <option value={256}>256 Bit</option>
</Select> */} // </Select> */}
<Label>Pre-Shared Key</Label> // <Label>Pre-Shared Key</Label>
<Input // <Input
// width="100%" // // width="100%"
// label="Pre-Shared Key" // // label="Pre-Shared Key"
// description="Channel key to encrypt data" // // description="Channel key to encrypt data"
type={pskHidden ? "password" : "text"} // type={pskHidden ? "password" : "text"}
action={{ // action={{
icon: pskHidden ? EyeIcon : EyeOffIcon, // icon: pskHidden ? EyeIcon : EyeOffIcon,
onClick: () => { // onClick: () => {
setPskHidden(!pskHidden); // setPskHidden(!pskHidden);
// }
// }}
// // error={errors.psk?.message}
// {...register("psk")}
// />
// <Controller
// name="uplinkEnabled"
// control={control}
// render={({ field: { value, ...rest } }) => (
// <>
// <Label>Uplink Enabled</Label>
// <Switch
// // label="Uplink Enabled"
// // description="Send packets to designated MQTT server"
// checked={value}
// {...rest}
// />
// </>
// )}
// />
// <Controller
// name="downlinkEnabled"
// control={control}
// render={({ field: { value, ...rest } }) => (
// <>
// <Label>Downlink Enabled</Label>
// <Switch
// // label="Downlink Enabled"
// // description="Recieve packets to designated MQTT server"
// checked={value}
// {...rest}
// />
// </>
// )}
// />
// </form>
<DynamicForm<ChannelSettingsValidation>
onSubmit={onSubmit}
defaultValues={{
enabled: [
Protobuf.Channel_Role.SECONDARY,
Protobuf.Channel_Role.PRIMARY
].find((role) => role === channel?.role)
? true
: false,
...channel?.settings,
psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0))
}}
fieldGroups={[
{
label: "Bluetooth Settings",
description: "Settings for the Bluetooth module",
fields: [
{
type: "toggle",
name: "enabled",
label: "Enabled",
description: "Description"
},
{
type: "password",
name: "psk",
label: "pre-Shared Key",
description: "Description",
disabledBy: [
{
fieldName: "enabled"
}
],
properties: {
// act
}
},
{
type: "number",
name: "channelNum",
label: "Channel Number",
description: "Description",
disabledBy: [
{
fieldName: "enabled"
}
]
},
{
type: "text",
name: "name",
label: "Name",
description: "Description",
disabledBy: [
{
fieldName: "enabled"
}
]
},
{
type: "number",
name: "id",
label: "ID",
description: "Description",
disabledBy: [
{
fieldName: "enabled"
}
]
},
{
type: "toggle",
name: "uplinkEnabled",
label: "Uplink Enabled",
description: "Description",
disabledBy: [
{
fieldName: "enabled"
}
]
},
{
type: "toggle",
name: "downlinkEnabled",
label: "Downlink Enabled",
description: "Description",
disabledBy: [
{
fieldName: "enabled"
}
]
} }
}} ]
// error={errors.psk?.message} }
{...register("psk")} ]}
/> />
<Controller
name="uplinkEnabled"
control={control}
render={({ field: { value, ...rest } }) => (
<>
<Label>Uplink Enabled</Label>
<Switch
// label="Uplink Enabled"
// description="Send packets to designated MQTT server"
checked={value}
{...rest}
/>
</>
)}
/>
<Controller
name="downlinkEnabled"
control={control}
render={({ field: { value, ...rest } }) => (
<>
<Label>Downlink Enabled</Label>
<Switch
// label="Downlink Enabled"
// description="Recieve packets to designated MQTT server"
checked={value}
{...rest}
/>
</>
)}
/>
</form>
</div>
); );
}; };

8
src/pages/Config/index.tsx

@ -55,13 +55,7 @@ export const ConfigPage = (): JSX.Element => {
} }
]} ]}
> >
<div className="p-3"> {activeConfigSection === "device" ? <DeviceConfig /> : <ModuleConfig />}
{activeConfigSection === "device" ? (
<DeviceConfig />
) : (
<ModuleConfig />
)}
</div>
</PageLayout> </PageLayout>
</> </>
); );

2
src/pages/Map.tsx

@ -13,7 +13,6 @@ import {
} from "lucide-react"; } from "lucide-react";
import { bbox, lineString } from "@turf/turf"; import { bbox, lineString } from "@turf/turf";
import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.js"; import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.js";
import { Button } from "@components/UI/Button.js";
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.js"; import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.js";
import { Protobuf } from "@meshtastic/meshtasticjs"; import { Protobuf } from "@meshtastic/meshtasticjs";
@ -61,6 +60,7 @@ export const MapPage = (): JSX.Element => {
</Sidebar> </Sidebar>
<PageLayout <PageLayout
label="Map" label="Map"
noPadding
actions={[ actions={[
{ {
icon: ZoomInIcon, icon: ZoomInIcon,

15
src/validation/channelSettings.ts

@ -1,4 +1,11 @@
import { IsBoolean, IsInt, IsNumber, IsString, Length } from "class-validator"; import {
IsBoolean,
IsEnum,
IsInt,
IsNumber,
IsString,
Length
} from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs"; import type { Protobuf } from "@meshtastic/meshtasticjs";
@ -9,12 +16,12 @@ export class ChannelSettingsValidation
@IsBoolean() @IsBoolean()
enabled: boolean; enabled: boolean;
@IsString()
psk: string;
@IsNumber() @IsNumber()
channelNum: number; channelNum: number;
@IsString()
psk: string;
@Length(0, 11) @Length(0, 11)
name: string; name: string;

Loading…
Cancel
Save