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. 405
      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" />

405
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,29 +14,175 @@ 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(() => {
// reset({
// 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))
// });
// }, [channel, reset]);
useEffect(() => { // const onSubmit = handleSubmit((data) => {
reset({ // connection
// ?.setChannel(
// new Protobuf.Channel({
// role:
// channel?.role === Protobuf.Channel_Role.PRIMARY
// ? Protobuf.Channel_Role.PRIMARY
// : data.enabled
// ? Protobuf.Channel_Role.SECONDARY
// : Protobuf.Channel_Role.DISABLED,
// index: channel?.index,
// settings: {
// ...data,
// psk: toByteArray(data.psk ?? "")
// }
// })
// )
// .then(() =>
// addChannel({
// config: new Protobuf.Channel({
// index: channel.index,
// role: channel.role,
// settings: {
// ...data,
// psk: toByteArray(data.psk ?? "")
// }
// }),
// lastInterraction: new Date(),
// messages: []
// })
// );
// });
const onSubmit = (data: ChannelSettingsValidation) => {
console.log(data);
};
return (
// <div className="p-3">
// <form onSubmit={onSubmit}>
// {channel?.index !== 0 && (
// <>
// <Controller
// name="enabled"
// control={control}
// render={({ field: { value, ...rest } }) => (
// <>
// <Label>Enabled</Label>
// <Switch
// // label="Enabled"
// // description="Description"
// checked={value}
// {...rest}
// />
// </>
// )}
// />
// <Label>Name</Label>
// <Input
// // description="Max transmit power in dBm"
// // error={errors.name?.message}
// {...register("name")}
// />
// </>
// )}
// {/* <Select
// label="Key Size"
// description="Desired size of generated key."
// value={keySize}
// onChange={(e): void => {
// setKeySize(parseInt(e.target.value) as 128 | 256);
// }}
// action={{
// icon: <RefreshCwIcon size={16} />,
// action: () => {
// const key = new Uint8Array(keySize / 8);
// crypto.getRandomValues(key);
// setValue("psk", fromByteArray(key), {
// shouldDirty: true
// });
// }
// }}
// >
// <option value={128}>128 Bit</option>
// <option value={256}>256 Bit</option>
// </Select> */}
// <Label>Pre-Shared Key</Label>
// <Input
// // width="100%"
// // label="Pre-Shared Key"
// // description="Channel key to encrypt data"
// type={pskHidden ? "password" : "text"}
// action={{
// icon: pskHidden ? EyeIcon : EyeOffIcon,
// onClick: () => {
// 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: [ enabled: [
Protobuf.Channel_Role.SECONDARY, Protobuf.Channel_Role.SECONDARY,
Protobuf.Channel_Role.PRIMARY Protobuf.Channel_Role.PRIMARY
@ -50,137 +191,91 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
: false, : false,
...channel?.settings, ...channel?.settings,
psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0)) psk: fromByteArray(channel?.settings?.psk ?? new Uint8Array(0))
}); }}
}, [channel, reset]); 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",
const onSubmit = handleSubmit((data) => { disabledBy: [
connection {
?.setChannel( fieldName: "enabled"
new Protobuf.Channel({
role:
channel?.role === Protobuf.Channel_Role.PRIMARY
? Protobuf.Channel_Role.PRIMARY
: data.enabled
? Protobuf.Channel_Role.SECONDARY
: Protobuf.Channel_Role.DISABLED,
index: channel?.index,
settings: {
...data,
psk: toByteArray(data.psk ?? "")
} }
}) ],
) properties: {
.then(() => // act
addChannel({
config: new Protobuf.Channel({
index: channel.index,
role: channel.role,
settings: {
...data,
psk: toByteArray(data.psk ?? "")
} }
}), },
lastInterraction: new Date(), {
messages: [] type: "number",
}) name: "channelNum",
); label: "Channel Number",
}); description: "Description",
disabledBy: [
return ( {
<div className="p-3"> fieldName: "enabled"
<form onSubmit={onSubmit}>
{channel?.index !== 0 && (
<>
<Controller
name="enabled"
control={control}
render={({ field: { value, ...rest } }) => (
<>
<Label>Enabled</Label>
<Switch
// label="Enabled"
// description="Description"
checked={value}
{...rest}
/>
</>
)}
/>
<Label>Name</Label>
<Input
// description="Max transmit power in dBm"
// error={errors.name?.message}
{...register("name")}
/>
</>
)}
{/* <Select
label="Key Size"
description="Desired size of generated key."
value={keySize}
onChange={(e): void => {
setKeySize(parseInt(e.target.value) as 128 | 256);
}}
action={{
icon: <RefreshCwIcon size={16} />,
action: () => {
const key = new Uint8Array(keySize / 8);
crypto.getRandomValues(key);
setValue("psk", fromByteArray(key), {
shouldDirty: true
});
} }
}} ]
> },
<option value={128}>128 Bit</option> {
<option value={256}>256 Bit</option> type: "text",
</Select> */} name: "name",
<Label>Pre-Shared Key</Label> label: "Name",
<Input description: "Description",
// width="100%" disabledBy: [
// label="Pre-Shared Key" {
// description="Channel key to encrypt data" fieldName: "enabled"
type={pskHidden ? "password" : "text"}
action={{
icon: pskHidden ? EyeIcon : EyeOffIcon,
onClick: () => {
setPskHidden(!pskHidden);
} }
}} ]
// error={errors.psk?.message} },
{...register("psk")} {
/> type: "number",
<Controller name: "id",
name="uplinkEnabled" label: "ID",
control={control} description: "Description",
render={({ field: { value, ...rest } }) => ( disabledBy: [
<> {
<Label>Uplink Enabled</Label> fieldName: "enabled"
<Switch }
// label="Uplink Enabled" ]
// description="Send packets to designated MQTT server" },
checked={value} {
{...rest} type: "toggle",
/> name: "uplinkEnabled",
</> label: "Uplink Enabled",
)} description: "Description",
/> disabledBy: [
<Controller {
name="downlinkEnabled" fieldName: "enabled"
control={control} }
render={({ field: { value, ...rest } }) => ( ]
<> },
<Label>Downlink Enabled</Label> {
<Switch type: "toggle",
// label="Downlink Enabled" name: "downlinkEnabled",
// description="Recieve packets to designated MQTT server" label: "Downlink Enabled",
checked={value} description: "Description",
{...rest} disabledBy: [
/> {
</> fieldName: "enabled"
)} }
]
}
]
}
]}
/> />
</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