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 w-40 flex-col gap-1">
{channels.map((channel) => (
<>
<div key={channel.index}>
<Label>
{channel.settings?.name.length
? channel.settings.name
@ -87,7 +87,7 @@ export const QRDialog = ({
}
}}
/>
</>
</div>
))}
</div>
<QRCode value={QRCodeURL} size={200} qrStyle="dots" />

425
src/components/PageComponents/Channel.tsx

@ -1,14 +1,9 @@
import { useEffect, useState } from "react";
import { fromByteArray, toByteArray } from "base64-js";
import { Controller, useForm } from "react-hook-form";
import { ChannelSettingsValidation } from "@app/validation/channelSettings.js";
import { Input } from "@components/UI/Input.js";
import { Switch } from "@components/UI/Switch.js";
import type { ChannelSettingsValidation } from "@app/validation/channelSettings.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 { Label } from "@radix-ui/react-label";
import { DynamicForm } from "../Form/DynamicForm.js";
export interface SettingsPanelProps {
channel: Protobuf.Channel;
@ -19,168 +14,268 @@ export const Channel = ({ channel }: SettingsPanelProps): JSX.Element => {
const [keySize, setKeySize] = useState<128 | 256>(256);
const [pskHidden, setPskHidden] = useState(true);
const {
register,
handleSubmit,
formState: { errors, isDirty },
reset,
control,
setValue
} = useForm<ChannelSettingsValidation>({
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))
},
resolver: classValidatorResolver(ChannelSettingsValidation)
});
// const {
// register,
// handleSubmit,
// formState: { errors, isDirty },
// reset,
// control,
// setValue
// } = useForm<ChannelSettingsValidation>({
// 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))
// },
// 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(() => {
// 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]);
const onSubmit = handleSubmit((data) => {
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 = handleSubmit((data) => {
// 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);
// <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: [
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 />
)}
</div>
{activeConfigSection === "device" ? <DeviceConfig /> : <ModuleConfig />}
</PageLayout>
</>
);

2
src/pages/Map.tsx

@ -13,7 +13,6 @@ import {
} from "lucide-react";
import { bbox, lineString } from "@turf/turf";
import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.js";
import { Button } from "@components/UI/Button.js";
import { SidebarButton } from "@components/UI/Sidebar/sidebarButton.js";
import { Protobuf } from "@meshtastic/meshtasticjs";
@ -61,6 +60,7 @@ export const MapPage = (): JSX.Element => {
</Sidebar>
<PageLayout
label="Map"
noPadding
actions={[
{
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";
@ -9,12 +16,12 @@ export class ChannelSettingsValidation
@IsBoolean()
enabled: boolean;
@IsString()
psk: string;
@IsNumber()
channelNum: number;
@IsString()
psk: string;
@Length(0, 11)
name: string;

Loading…
Cancel
Save