Updated channel editor + fixes
This commit is contained in:
+32
-38
@@ -13,13 +13,17 @@ import { IconButton } from './generic/IconButton';
|
||||
|
||||
export interface ChannelProps {
|
||||
channel: Protobuf.Channel;
|
||||
hideEnabled?: boolean;
|
||||
}
|
||||
|
||||
export const Channel = ({ channel }: ChannelProps): JSX.Element => {
|
||||
export const Channel = ({
|
||||
channel,
|
||||
hideEnabled,
|
||||
}: ChannelProps): JSX.Element => {
|
||||
const [edit, setEdit] = React.useState(false);
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
|
||||
const { register, handleSubmit, formState } = useForm<{
|
||||
const { register, handleSubmit } = useForm<{
|
||||
enabled: boolean;
|
||||
settings: {
|
||||
name: string;
|
||||
@@ -33,11 +37,12 @@ export const Channel = ({ channel }: ChannelProps): JSX.Element => {
|
||||
};
|
||||
}>({
|
||||
defaultValues: {
|
||||
enabled:
|
||||
channel.role ===
|
||||
(Protobuf.Channel_Role.PRIMARY || Protobuf.Channel_Role.SECONDARY)
|
||||
? true
|
||||
: false,
|
||||
enabled: [
|
||||
Protobuf.Channel_Role.SECONDARY,
|
||||
Protobuf.Channel_Role.PRIMARY,
|
||||
].find((role) => role === channel.role)
|
||||
? true
|
||||
: false,
|
||||
settings: {
|
||||
name: channel.settings?.name,
|
||||
bandwidth: channel.settings?.bandwidth,
|
||||
@@ -54,9 +59,12 @@ export const Channel = ({ channel }: ChannelProps): JSX.Element => {
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
setLoading(true);
|
||||
const adminChannel = Protobuf.Channel.create({
|
||||
role: data.enabled
|
||||
? Protobuf.Channel_Role.SECONDARY
|
||||
: Protobuf.Channel_Role.DISABLED,
|
||||
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.settings,
|
||||
@@ -75,41 +83,24 @@ export const Channel = ({ channel }: ChannelProps): JSX.Element => {
|
||||
{edit ? (
|
||||
<>
|
||||
{loading && <Loading />}
|
||||
<div className="my-auto space-x-2">
|
||||
<form>
|
||||
<div className="flex space-x-2">
|
||||
{/* @todo: change to disable & make primary buttons */}
|
||||
<div className="flex my-auto">
|
||||
{/* TODO: get gap working */}
|
||||
<form className="gap-3">
|
||||
{/* @todo: change to disable & make primary buttons */}
|
||||
{!hideEnabled && (
|
||||
<Checkbox
|
||||
label="Enabled"
|
||||
{...register('enabled', { valueAsNumber: true })}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<Input label="Name" {...register('settings.name')} />
|
||||
<Input label="Pre-Shared Key" {...register('settings.psk')} />
|
||||
<Input
|
||||
label="Bandwidth"
|
||||
type="number"
|
||||
{...register('settings.bandwidth', { valueAsNumber: true })}
|
||||
/>
|
||||
<Input
|
||||
label="Spread Factor"
|
||||
type="number"
|
||||
min={7}
|
||||
max={12}
|
||||
{...register('settings.spreadFactor', { valueAsNumber: true })}
|
||||
/>
|
||||
<Input
|
||||
label="Coding Rate"
|
||||
type="number"
|
||||
{...register('settings.codingRate', { valueAsNumber: true })}
|
||||
/>
|
||||
<Input
|
||||
label="Transmit Power"
|
||||
type="number"
|
||||
{...register('settings.txPower', { valueAsNumber: true })}
|
||||
label="Pre-Shared Key"
|
||||
type="password"
|
||||
{...register('settings.psk')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Upling Enabled"
|
||||
label="Uplink Enabled"
|
||||
{...register('settings.uplinkEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
@@ -132,7 +123,10 @@ export const Channel = ({ channel }: ChannelProps): JSX.Element => {
|
||||
<div className="flex my-auto space-x-2">
|
||||
<div
|
||||
className={`h-3 my-auto w-3 rounded-full ${
|
||||
channel.role === Protobuf.Channel_Role.SECONDARY
|
||||
[
|
||||
Protobuf.Channel_Role.SECONDARY,
|
||||
Protobuf.Channel_Role.PRIMARY,
|
||||
].find((role) => role === channel.role)
|
||||
? 'bg-green-500'
|
||||
: 'bg-gray-400'
|
||||
}`}
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useForm } from 'react-hook-form';
|
||||
|
||||
import { Loading } from '@components/generic/Loading';
|
||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||
|
||||
import { connection } from '../core/connection';
|
||||
import { Card } from './generic/Card';
|
||||
import { Checkbox } from './generic/form/Checkbox';
|
||||
import { Input } from './generic/form/Input';
|
||||
|
||||
export interface LoraConfigProps {
|
||||
channel: Protobuf.Channel;
|
||||
}
|
||||
|
||||
export const LoraConfig = ({ channel }: LoraConfigProps): JSX.Element => {
|
||||
const [loading, setLoading] = React.useState(false);
|
||||
|
||||
const { register, handleSubmit } = useForm<{
|
||||
enabled: boolean;
|
||||
settings: {
|
||||
name: string;
|
||||
bandwidth?: number;
|
||||
codingRate?: number;
|
||||
spreadFactor?: number;
|
||||
downlinkEnabled?: boolean;
|
||||
uplinkEnabled?: boolean;
|
||||
txPower?: number;
|
||||
psk?: string;
|
||||
};
|
||||
}>({
|
||||
defaultValues: {
|
||||
enabled:
|
||||
channel.role ===
|
||||
(Protobuf.Channel_Role.PRIMARY || Protobuf.Channel_Role.SECONDARY)
|
||||
? true
|
||||
: false,
|
||||
settings: {
|
||||
name: channel.settings?.name,
|
||||
bandwidth: channel.settings?.bandwidth,
|
||||
codingRate: channel.settings?.codingRate,
|
||||
spreadFactor: channel.settings?.spreadFactor,
|
||||
downlinkEnabled: channel.settings?.downlinkEnabled,
|
||||
uplinkEnabled: channel.settings?.uplinkEnabled,
|
||||
txPower: channel.settings?.txPower,
|
||||
psk: new TextDecoder().decode(channel.settings?.psk),
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
setLoading(true);
|
||||
const adminChannel = Protobuf.Channel.create({
|
||||
role: data.enabled
|
||||
? Protobuf.Channel_Role.SECONDARY
|
||||
: Protobuf.Channel_Role.DISABLED,
|
||||
index: channel.index,
|
||||
settings: {
|
||||
...data.settings,
|
||||
psk: new TextEncoder().encode(data.settings.psk),
|
||||
},
|
||||
});
|
||||
|
||||
await connection.setChannel(adminChannel, (): Promise<void> => {
|
||||
setLoading(false);
|
||||
return Promise.resolve();
|
||||
});
|
||||
});
|
||||
|
||||
return (
|
||||
<Card>
|
||||
{loading && <Loading />}
|
||||
<div className="w-full max-w-3xl p-10 md:max-w-xl">
|
||||
{/* TODO: get gap working */}
|
||||
<form onSubmit={onSubmit}>
|
||||
<Input
|
||||
label="Bandwidth"
|
||||
type="number"
|
||||
suffix="MHz"
|
||||
{...register('settings.bandwidth', { valueAsNumber: true })}
|
||||
/>
|
||||
<Input
|
||||
label="Spread Factor"
|
||||
type="number"
|
||||
suffix="CPS"
|
||||
min={7}
|
||||
max={12}
|
||||
{...register('settings.spreadFactor', {
|
||||
valueAsNumber: true,
|
||||
})}
|
||||
/>
|
||||
<Input
|
||||
label="Coding Rate"
|
||||
type="number"
|
||||
{...register('settings.codingRate', { valueAsNumber: true })}
|
||||
/>
|
||||
<Input
|
||||
label="Transmit Power"
|
||||
type="number"
|
||||
suffix="dBm"
|
||||
{...register('settings.txPower', { valueAsNumber: true })}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Uplink Enabled"
|
||||
{...register('settings.uplinkEnabled')}
|
||||
/>
|
||||
<Checkbox
|
||||
label="Downlink Enabled"
|
||||
{...register('settings.downlinkEnabled')}
|
||||
/>
|
||||
</form>
|
||||
</div>
|
||||
</Card>
|
||||
);
|
||||
};
|
||||
@@ -9,10 +9,12 @@ interface InputProps extends DefaultInputProps {
|
||||
label?: string;
|
||||
error?: string;
|
||||
action?: JSX.Element;
|
||||
prefix?: string;
|
||||
suffix?: string;
|
||||
}
|
||||
|
||||
export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
function Input({ label, error, action, ...props }: InputProps, ref) {
|
||||
function Input({ label, error, action, suffix, ...props }: InputProps, ref) {
|
||||
return (
|
||||
<div className="w-full">
|
||||
{label && <Label label={label} error={error} />}
|
||||
@@ -22,6 +24,11 @@ export const Input = React.forwardRef<HTMLInputElement, InputProps>(
|
||||
className="w-full h-10 px-3 py-2 bg-transparent focus:outline-none"
|
||||
{...props}
|
||||
/>
|
||||
{suffix && (
|
||||
<span className="my-auto mr-3 text-sm font-medium text-gray-500 dark:text-gray-400">
|
||||
{suffix}
|
||||
</span>
|
||||
)}
|
||||
{action && <div className="flex mr-1">{action}</div>}
|
||||
</InputWrapper>
|
||||
</div>
|
||||
|
||||
@@ -30,7 +30,7 @@ export const Select = React.forwardRef<HTMLSelectElement, SelectProps>(
|
||||
<select
|
||||
ref={ref}
|
||||
className={`w-full rounded-md bg-transparent focus:outline-none focus:border-primary ${
|
||||
small ? 'p-1' : 'h-10 px-2'
|
||||
small ? 'm-1' : 'h-10 mx-2'
|
||||
}`}
|
||||
disabled={
|
||||
props.disabled
|
||||
|
||||
@@ -1,12 +1,6 @@
|
||||
import type React from 'react';
|
||||
|
||||
import {
|
||||
FiGrid,
|
||||
FiInfo,
|
||||
FiMessageSquare,
|
||||
FiPackage,
|
||||
FiSettings,
|
||||
} from 'react-icons/fi';
|
||||
import { FiGrid, FiMessageSquare, FiPackage, FiSettings } from 'react-icons/fi';
|
||||
|
||||
import { Button } from '@components/generic/Button';
|
||||
import { routes, useRoute } from '@core/router';
|
||||
@@ -66,16 +60,6 @@ export const Navigation = ({
|
||||
Settings
|
||||
</Button>
|
||||
</div>
|
||||
<div onClick={onClick}>
|
||||
<Button
|
||||
icon={<FiInfo className="w-6 h-6" />}
|
||||
className="w-full md:w-auto"
|
||||
active={route.name === 'about'}
|
||||
{...routes.about().link}
|
||||
>
|
||||
About
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user