Internal rework

This commit is contained in:
Sacha Weatherstone
2021-11-21 00:28:24 +11:00
parent 1f8170130d
commit 0cea0b2165
34 changed files with 903 additions and 803 deletions
+18 -16
View File
@@ -1,4 +1,4 @@
import type React from 'react';
import React from 'react';
import { FiHash } from 'react-icons/fi';
@@ -10,9 +10,9 @@ import { Protobuf } from '@meshtastic/meshtasticjs';
import { useAppSelector } from '../hooks/redux';
export const Messages = (): JSX.Element => {
const messages = useAppSelector((state) => state.meshtastic.messages);
const users = useAppSelector((state) => state.meshtastic.users);
const channels = useAppSelector((state) => state.meshtastic.channels);
const nodes = useAppSelector((state) => state.meshtastic.nodes);
const channels = useAppSelector((state) => state.meshtastic.radio.channels);
const [channelIndex, setChannelIndex] = React.useState(0);
return (
<div className="flex flex-col w-full">
@@ -23,25 +23,28 @@ export const Messages = (): JSX.Element => {
options={channels
.filter(
(channel) =>
channel.role !== Protobuf.Channel_Role.DISABLED &&
channel.settings?.name !== 'admin',
channel.channel.role !== Protobuf.Channel_Role.DISABLED &&
channel.channel.settings?.name !== 'admin',
)
.map((channel) => {
return {
name: channel.settings?.name.length
? channel.settings.name
: channel.role === Protobuf.Channel_Role.PRIMARY
name: channel.channel.settings?.name.length
? channel.channel.settings.name
: channel.channel.role === Protobuf.Channel_Role.PRIMARY
? 'Primary'
: `CH: ${channel.index}`,
value: channel.index,
: `CH: ${channel.channel.index}`,
value: channel.channel.index,
};
})}
onChange={(e): void => {
setChannelIndex(parseInt(e.target.value));
}}
small
/>
</div>
</div>
<div className="flex flex-col flex-grow p-6 space-y-2 overflow-y-auto bg-white border-b border-gray-300 md:py-8 md:px-10 dark:border-gray-600 dark:bg-secondaryDark">
{messages.map((message, index) => (
{channels[channelIndex]?.messages.map((message, index) => (
<Message
key={index}
isSender={message.isSender}
@@ -49,14 +52,13 @@ export const Messages = (): JSX.Element => {
ack={message.ack}
rxTime={new Date()}
senderName={
users.find(
(user) => user.packet.from === message.message.packet.from,
)?.data.longName ?? 'UNK'
nodes.find((node) => node.number === message.message.packet.from)
?.user?.longName ?? 'UNK'
}
/>
))}
</div>
<MessageBar />
<MessageBar channelIndex={channelIndex} />
</div>
);
};
+10 -7
View File
@@ -9,23 +9,26 @@ import { Protobuf } from '@meshtastic/meshtasticjs';
import { Node } from './Node';
export const Nodes = (): JSX.Element => {
const nodes = useAppSelector((state) => state.meshtastic.nodes);
const users = useAppSelector((state) => state.meshtastic.users);
const myNodeNum = useAppSelector(
(state) => state.meshtastic.radio.hardware,
).myNodeNum;
const nodes = useAppSelector((state) => state.meshtastic.nodes).filter(
(node) => node.number !== myNodeNum,
);
return (
<PageLayout
title="Nodes"
emptyMessage="No nodes discovered yet..."
sidebarItems={nodes.map((node) => {
const user = users.find((user) => user.packet.from === node.num)?.data;
return {
title: user ? user.longName : node.num.toString(),
description: user
? Protobuf.HardwareModel[user.hwModel]
title: node.user?.longName ?? node.number.toString(),
description: node.user
? Protobuf.HardwareModel[node.user.hwModel]
: 'Unknown Hardware',
icon: (
<Avatar
size={30}
name={user ? user.longName : node.num.toString()}
name={node.user?.longName ?? node.number.toString()}
variant="beam"
colors={['#213435', '#46685B', '#648A64', '#A6B985', '#E1E3AC']}
/>
+7 -33
View File
@@ -6,33 +6,24 @@ import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import TimeAgo from 'timeago-react';
import { Cover } from '@app/components/generic/Cover';
import { useAppSelector } from '@app/hooks/redux';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { Cover } from '@components/generic/Cover';
import { IconButton } from '@components/generic/IconButton';
import { StatCard } from '@components/generic/StatCard';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import type { Protobuf } from '@meshtastic/meshtasticjs';
import type { Node as NodeType } from '@core/slices/meshtasticSlice';
export interface NodeProps {
navOpen?: boolean;
setNavOpen?: React.Dispatch<React.SetStateAction<boolean>>;
node: Protobuf.NodeInfo;
node: NodeType;
}
export const Node = ({ navOpen, setNavOpen, node }: NodeProps): JSX.Element => {
const user = useAppSelector((state) => state.meshtastic.users).find(
(user) => user.packet.from === node.num,
)?.data;
const position = useAppSelector(
(state) => state.meshtastic.positionPackets,
).find((position) => position.packet.from === node.num)?.data;
const [debug, setDebug] = React.useState(false);
return (
<PrimaryTemplate
title={user ? user.longName : node.num.toString()}
title={node.user?.longName ?? node.number.toString()}
tagline="Node"
leftButton={
<IconButton
@@ -51,38 +42,21 @@ export const Node = ({ navOpen, setNavOpen, node }: NodeProps): JSX.Element => {
}}
/>
}
footer={<></>}
>
<div className="w-full space-y-4">
<div className="flex flex-col justify-between gap-4 md:flex-row">
<StatCard
title="Last heard"
value={
node.lastHeard ? (
<TimeAgo datetime={new Date(node.lastHeard * 1000)} />
) : (
'Never'
)
node.lastHeard ? <TimeAgo datetime={node.lastHeard} /> : 'Never'
}
/>
<StatCard title="SNR" value={node.snr.toString()} />
</div>
<Card
title="Position"
description={new Date(node.lastHeard * 1000).toLocaleString()}
>
<Card title="Position" description={node.lastHeard.toLocaleString()}>
<Cover enabled={debug} content={<JSONPretty data={node} />} />
<div className="p-10">
<JSONPretty data={position} />
</div>
</Card>
<Card title="Settings" description="Remote node settings">
<div className="p-10">
<form className="space-y-4">
<Input label="Device Name" />
<Input label="Short Name" maxLength={3} />
<Checkbox label="Licenced Operator?" />
</form>
<JSONPretty data={node.positions[node.positions.length - 1]} />
</div>
</Card>
</div>
+18 -3
View File
@@ -1,16 +1,16 @@
import type React from 'react';
import React from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { FiMenu } from 'react-icons/fi';
import { FormFooter } from '@app/components/FormFooter';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
export interface ExternalNotificationProps {
@@ -22,7 +22,9 @@ export const ExternalNotification = ({
navOpen,
setNavOpen,
}: ExternalNotificationProps): JSX.Element => {
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const { register, handleSubmit, formState, reset, control } =
useForm<RadioConfig_UserPreferences>({
@@ -39,6 +41,19 @@ export const ExternalNotification = ({
},
});
React.useEffect(() => {
reset({
extNotificationPluginActive: preferences.extNotificationPluginActive,
extNotificationPluginAlertBell:
preferences.extNotificationPluginAlertBell,
extNotificationPluginAlertMessage:
preferences.extNotificationPluginAlertMessage,
extNotificationPluginEnabled: preferences.extNotificationPluginEnabled,
extNotificationPluginOutput: preferences.extNotificationPluginOutput,
extNotificationPluginOutputMs: preferences.extNotificationPluginOutputMs,
});
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
void connection.setPreferences(data);
});
+5 -17
View File
@@ -4,11 +4,11 @@ import type React from 'react';
import { FiMenu, FiTrash, FiUploadCloud } from 'react-icons/fi';
import useSWR from 'swr';
import fetcher from '@app/core/utils/fetcher';
import { useAppSelector } from '@app/hooks/redux';
import { Card } from '@components/generic/Card';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connectionUrl } from '@core/connection';
import fetcher from '@core/utils/fetcher';
export interface RangeTestProps {
navOpen?: boolean;
@@ -33,20 +33,8 @@ interface IFiles {
}
export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
const hostOverrideEnabled = useAppSelector(
(state) => state.meshtastic.hostOverrideEnabled,
);
const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride);
const connectionURL = hostOverrideEnabled
? hostOverride
: import.meta.env.PROD
? window.location.hostname
: (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
'http://meshtastic.local';
const { data } = useSWR<IFiles>(
`http://${connectionURL}/json/spiffs/browse/static`,
`http://${connectionUrl}/json/spiffs/browse/static`,
fetcher,
);
@@ -107,7 +95,7 @@ export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
/> */}
</div>
<a
href={`http://${connectionURL}/${file.name.replace(
href={`http://${connectionUrl}/${file.name.replace(
'static/',
'',
)}`}
@@ -120,7 +108,7 @@ export const Files = ({ navOpen, setNavOpen }: RangeTestProps): JSX.Element => {
className="mx-2 my-auto"
// confirmAction={async (): Promise<void> => {
// await fetch(
// `http://${connectionURL}/json/spiffs/delete/static?remove=${file.name}`,
// `http://${connectionUrl}/json/spiffs/delete/static?remove=${file.name}`,
// {
// method: 'DELETE',
// },
+14 -4
View File
@@ -1,16 +1,16 @@
import type React from 'react';
import React from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { FiMenu } from 'react-icons/fi';
import { FormFooter } from '@app/components/FormFooter';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
export interface RangeTestProps {
@@ -22,7 +22,9 @@ export const RangeTest = ({
navOpen,
setNavOpen,
}: RangeTestProps): JSX.Element => {
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const { register, handleSubmit, formState, reset, control } =
useForm<RadioConfig_UserPreferences>({
@@ -33,6 +35,14 @@ export const RangeTest = ({
},
});
React.useEffect(() => {
reset({
rangeTestPluginEnabled: preferences.rangeTestPluginEnabled,
rangeTestPluginSave: preferences.rangeTestPluginSave,
rangeTestPluginSender: preferences.rangeTestPluginSender,
});
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
void connection.setPreferences(data);
});
+17 -4
View File
@@ -1,16 +1,16 @@
import type React from 'react';
import React from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { FiMenu } from 'react-icons/fi';
import { FormFooter } from '@app/components/FormFooter';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import type { RadioConfig_UserPreferences } from '@meshtastic/meshtasticjs/dist/generated';
export interface SerialProps {
@@ -19,7 +19,9 @@ export interface SerialProps {
}
export const Serial = ({ navOpen, setNavOpen }: SerialProps): JSX.Element => {
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const { register, handleSubmit, formState, reset, control } =
useForm<RadioConfig_UserPreferences>({
@@ -33,6 +35,17 @@ export const Serial = ({ navOpen, setNavOpen }: SerialProps): JSX.Element => {
},
});
React.useEffect(() => {
reset({
serialpluginEnabled: preferences.serialpluginEnabled,
serialpluginEcho: preferences.serialpluginEcho,
serialpluginMode: preferences.serialpluginMode,
serialpluginRxd: preferences.serialpluginRxd,
serialpluginTimeout: preferences.serialpluginTimeout,
serialpluginTxd: preferences.serialpluginTxd,
});
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
void connection.setPreferences(data);
});
+7 -7
View File
@@ -3,15 +3,15 @@ import React from 'react';
import { FiCode, FiMenu, FiSave } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { LoraConfig } from '@app/components/LoraConfig';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { Channel } from '@components/Channel';
import { Button } from '@components/generic/Button';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { IconButton } from '@components/generic/IconButton';
import { LoraConfig } from '@components/LoraConfig';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
export interface ChannelsProps {
navOpen?: boolean;
@@ -22,7 +22,7 @@ export const Channels = ({
navOpen,
setNavOpen,
}: ChannelsProps): JSX.Element => {
const channels = useAppSelector((state) => state.meshtastic.channels);
const channels = useAppSelector((state) => state.meshtastic.radio.channels);
const [debug, setDebug] = React.useState(false);
return (
@@ -58,15 +58,15 @@ export const Channels = ({
}
>
<div className="space-y-4">
{channels[0] && <LoraConfig channel={channels[0]} />}
{channels[0] && <LoraConfig channel={channels[0].channel} />}
<Card>
<Cover enabled={debug} content={<JSONPretty data={channels} />} />
<div className="w-full p-4 space-y-2 md:p-10">
{channels.map((channel) => (
<Channel
key={channel.index}
channel={channel}
hideEnabled={channel.index === 0}
key={channel.channel.index}
channel={channel.channel}
hideEnabled={channel.channel.index === 0}
/>
))}
-271
View File
@@ -1,271 +0,0 @@
import React from 'react';
import { useForm } from 'react-hook-form';
import { FiCheck, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { FormFooter } from '@app/components/FormFooter';
import { ble, connection, serial, setConnection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { Button } from '@components/generic/Button';
import { Card } from '@components/generic/Card';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
} from '@meshtastic/meshtasticjs';
import type {
BLEConnectionParameters,
HTTPConnectionParameters,
SerialConnectionParameters,
} from '@meshtastic/meshtasticjs/dist/types';
export interface ConnectionProps {
navOpen?: boolean;
setNavOpen?: React.Dispatch<React.SetStateAction<boolean>>;
}
enum connType {
HTTP,
BLE,
SERIAL,
}
export const Connection = ({
navOpen,
setNavOpen,
}: ConnectionProps): JSX.Element => {
const [selectedConnType, setSelectedConnType] = React.useState(connType.HTTP);
const [bleDevices, setBleDevices] = React.useState<BluetoothDevice[]>([]);
const [serialDevices, setSerialDevices] = React.useState<SerialPort[]>([]);
const [httpIpSource, setHttpIpSource] = React.useState<'local' | 'remote'>(
'local',
);
const hostOverrideEnabled = useAppSelector(
(state) => state.meshtastic.hostOverrideEnabled,
);
const hostOverride = useAppSelector((state) => state.meshtastic.hostOverride);
const { formState, reset } = useForm<{
method: connType;
}>({
defaultValues: {
method: connType.HTTP,
},
});
const connect = async (
connectionType: connType,
params:
| HTTPConnectionParameters
| SerialConnectionParameters
| BLEConnectionParameters,
): Promise<void> => {
connection.complete();
connection.disconnect();
if (connectionType === connType.BLE) {
setConnection(new IBLEConnection());
} else if (connectionType === connType.HTTP) {
setConnection(new IHTTPConnection());
} else {
setConnection(new ISerialConnection());
}
// @ts-ignore tmp
await connection.connect(params);
};
const updateBleDeviceList = React.useCallback(async (): Promise<void> => {
const devices = await ble.getDevices();
setBleDevices(devices);
}, []);
const updateSerialDeviceList = React.useCallback(async (): Promise<void> => {
const devices = await serial.getPorts();
console.log(devices);
setSerialDevices(devices);
}, []);
React.useEffect(() => {
if (selectedConnType === connType.BLE) {
void updateBleDeviceList();
}
if (selectedConnType === connType.SERIAL) {
void updateSerialDeviceList();
}
}, [selectedConnType, updateBleDeviceList, updateSerialDeviceList]);
const connectionURL: string = hostOverrideEnabled
? hostOverride
: import.meta.env.PROD
? window.location.hostname
: (import.meta.env.VITE_PUBLIC_DEVICE_IP as string) ??
'http://meshtastic.local';
return (
<PrimaryTemplate
title="Connection"
tagline="Settings"
leftButton={
<IconButton
icon={<FiMenu className="w-5 h-5" />}
onClick={(): void => {
setNavOpen && setNavOpen(!navOpen);
}}
/>
}
footer={
<FormFooter
dirty={formState.isDirty}
saveAction={(): void => {
return;
}}
clearAction={reset}
/>
}
>
<Card>
<div className="w-full max-w-3xl p-10 md:max-w-xl">
<form className="space-y-2">
<Select
label="Method"
optionsEnum={connType}
value={selectedConnType}
onChange={(e): void => {
setSelectedConnType(parseInt(e.target.value));
}}
/>
{selectedConnType === connType.HTTP && (
<>
<Select
label="Host Source"
options={[
{
name: 'Local',
value: 'local',
},
{
name: 'Remote',
value: 'remote',
},
]}
value={httpIpSource}
onChange={(e): void => {
setHttpIpSource(e.target.value as 'local' | 'remote');
}}
/>
{httpIpSource === 'local' ? (
<Input label="Host" value={connectionURL} disabled />
) : (
<Input label="Host" />
)}
<Checkbox label="Use TLS?" />
</>
)}
{selectedConnType === connType.BLE && (
<div>
<div className="flex space-x-2">
<Button border onClick={updateBleDeviceList}>
Refresh List
</Button>
<Button
border
onClick={async (): Promise<void> => {
await ble.getDevice();
}}
>
New Device
</Button>
</div>
<div className="space-y-2">
<div>Previously connected devices</div>
{bleDevices.map((device, index) => (
<div
onClick={async (): Promise<void> => {
console.log('clicked');
await connect(connType.BLE, {
device: device,
});
}}
className="flex justify-between p-2 bg-gray-700 rounded-md"
key={index}
>
<div className="my-auto">{device.name}</div>
<IconButton
onClick={async (): Promise<void> => {
console.log('clicked');
await connect(connType.BLE, {
device: device,
});
}}
icon={<FiCheck />}
/>
</div>
))}
</div>
</div>
)}
{selectedConnType === connType.SERIAL && (
<div>
<div className="flex space-x-2">
<Button border onClick={updateSerialDeviceList}>
Refresh List
</Button>
<Button
border
onClick={async (): Promise<void> => {
console.log(await serial.getPort());
}}
>
New Device
</Button>
</div>
<div className="space-y-2">
<div>Previously connected devices</div>
{serialDevices.map((device, index) => (
<div
className="flex justify-between p-2 bg-gray-700 rounded-md"
key={index}
>
<div className="my-auto">
{device.getInfo().usbProductId}
{device.getInfo().usbVendorId}
</div>
<IconButton
onClick={async (): Promise<void> => {
await connect(connType.SERIAL, {
// @ts-ignore tmp
device: device,
});
}}
icon={<FiCheck />}
/>
<JSONPretty data={device.getInfo()} />
</div>
))}
</div>
</div>
)}
</form>
<Button
border
onClick={(): void => {
connection.disconnect();
}}
>
Disconnect
</Button>
</div>
</Card>
</PrimaryTemplate>
);
};
-8
View File
@@ -3,7 +3,6 @@ import type React from 'react';
import {
FiLayers,
FiLayout,
FiLink2,
FiMapPin,
FiRadio,
FiUser,
@@ -14,7 +13,6 @@ import {
import { PageLayout } from '@components/templates/PageLayout';
import { Channels } from './Channels';
import { Connection } from './Connection';
import { Interface } from './Interface';
import { Position } from './Position';
import { Power } from './Power';
@@ -24,11 +22,6 @@ import { WiFi } from './WiFi';
export const Settings = (): JSX.Element => {
const sidebarItems = [
{
title: 'Connection',
description: 'Connection method and parameters',
icon: <FiLink2 className="flex-shrink-0 w-6 h-6" />,
},
{
title: 'WiFi',
description: 'WiFi credentials and mode',
@@ -70,7 +63,6 @@ export const Settings = (): JSX.Element => {
title="Settings"
sidebarItems={sidebarItems}
panels={[
<Connection key={1} />,
<WiFi key={2} />,
<Position key={3} />,
<User key={4} />,
+1 -1
View File
@@ -3,11 +3,11 @@ import type React from 'react';
import { useTranslation } from 'react-i18next';
import { FiMenu, FiSave } from 'react-icons/fi';
import i18n from '@app/core/translation';
import { Button } from '@components/generic/Button';
import { Card } from '@components/generic/Card';
import { Select } from '@components/generic/form/Select';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import i18n from '@core/translation';
export interface InterfaceProps {
navOpen?: boolean;
+9 -3
View File
@@ -4,9 +4,8 @@ import { useForm } from 'react-hook-form';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { FormFooter } from '@app/components/FormFooter';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
@@ -14,6 +13,7 @@ import { Input } from '@components/generic/form/Input';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface PositionProps {
@@ -25,7 +25,9 @@ export const Position = ({
navOpen,
setNavOpen,
}: PositionProps): JSX.Element => {
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset } =
@@ -41,6 +43,10 @@ export const Position = ({
},
});
React.useEffect(() => {
reset(preferences);
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {
+10 -4
View File
@@ -4,15 +4,15 @@ import { useForm } from 'react-hook-form';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { FormFooter } from '@app/components/FormFooter';
import { Select } from '@app/components/generic/form/Select';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface PowerProps {
@@ -21,7 +21,9 @@ export interface PowerProps {
}
export const Power = ({ navOpen, setNavOpen }: PowerProps): JSX.Element => {
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset } =
@@ -32,6 +34,10 @@ export const Power = ({ navOpen, setNavOpen }: PowerProps): JSX.Element => {
},
});
React.useEffect(() => {
reset(preferences);
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {
+9 -3
View File
@@ -4,15 +4,15 @@ import { useForm } from 'react-hook-form';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { FormFooter } from '@app/components/FormFooter';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface RadioProps {
@@ -21,7 +21,9 @@ export interface RadioProps {
}
export const Radio = ({ navOpen, setNavOpen }: RadioProps): JSX.Element => {
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset } =
@@ -29,6 +31,10 @@ export const Radio = ({ navOpen, setNavOpen }: RadioProps): JSX.Element => {
defaultValues: preferences,
});
React.useEffect(() => {
reset(preferences);
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {
+31 -19
View File
@@ -5,8 +5,8 @@ import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { base16 } from 'rfc4648';
import { FormFooter } from '@app/components/FormFooter';
import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
@@ -15,7 +15,6 @@ import { Select } from '@components/generic/form/Select';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import { addUser } from '@core/slices/meshtasticSlice';
import { Protobuf } from '@meshtastic/meshtasticjs';
export interface UserProps {
@@ -26,10 +25,11 @@ export interface UserProps {
export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const dispatch = useAppDispatch();
const myNodeInfo = useAppSelector((state) => state.meshtastic.myNodeInfo);
const user = useAppSelector((state) => state.meshtastic.users).find(
(user) => user.packet.from === myNodeInfo.myNodeNum,
const myNodeNum = useAppSelector(
(state) => state.meshtastic.radio.hardware,
).myNodeNum;
const node = useAppSelector((state) => state.meshtastic.nodes).find(
(node) => node.number === myNodeNum,
);
const { register, handleSubmit, formState, reset } = useForm<{
longName: string;
@@ -38,22 +38,34 @@ export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
team: Protobuf.Team;
}>({
defaultValues: {
longName: user?.data.longName,
shortName: user?.data.shortName,
isLicensed: user?.data.isLicensed,
team: user?.data.team,
longName: node?.user?.longName,
shortName: node?.user?.shortName,
isLicensed: node?.user?.isLicensed,
team: node?.user?.team,
},
});
React.useEffect(() => {
reset({
longName: node?.user?.longName,
shortName: node?.user?.shortName,
isLicensed: node?.user?.isLicensed,
team: node?.user?.team,
});
}, [reset, node]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
// TODO: can be removed once getUser is implemented
if (user) {
void connection.setOwner({ ...user.data, ...data }, async () => {
if (node?.user) {
void connection.setOwner({ ...node.user, ...data }, async () => {
await Promise.resolve();
setLoading(false);
});
dispatch(addUser({ ...user, ...{ data: { ...user.data, ...data } } }));
// TODO: can be removed once getUser is implemented
// dispatch(
// addUser({ ...node.user, ...{ data: { ...node.user.data, ...data } } }),
// );
}
});
@@ -87,15 +99,15 @@ export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
}
>
<Card loading={loading}>
<Cover enabled={debug} content={<JSONPretty data={user?.data} />} />
<Cover enabled={debug} content={<JSONPretty data={node?.user} />} />
<div className="w-full max-w-3xl p-10 md:max-w-xl">
<form className="space-y-2" onSubmit={onSubmit}>
<Input label="Device ID" value={user?.data.id} disabled />
<Input label="Device ID" value={node?.user?.id} disabled />
<Input
label="Hardware"
value={
Protobuf.HardwareModel[
user?.data.hwModel ?? Protobuf.HardwareModel.UNSET
node?.user?.hwModel ?? Protobuf.HardwareModel.UNSET
]
}
disabled
@@ -104,7 +116,7 @@ export const User = ({ navOpen, setNavOpen }: UserProps): JSX.Element => {
label="Mac Address"
defaultValue={
base16
.stringify(user?.data.macaddr ?? [])
.stringify(node?.user?.macaddr ?? [])
.match(/.{1,2}/g)
?.join(':') ?? ''
}
+10 -4
View File
@@ -5,15 +5,15 @@ import { useTranslation } from 'react-i18next';
import { FiCode, FiMenu } from 'react-icons/fi';
import JSONPretty from 'react-json-pretty';
import { FormFooter } from '@app/components/FormFooter';
import { Checkbox } from '@app/components/generic/form/Checkbox';
import { connection } from '@app/core/connection';
import { useAppSelector } from '@app/hooks/redux';
import { FormFooter } from '@components/FormFooter';
import { Card } from '@components/generic/Card';
import { Cover } from '@components/generic/Cover';
import { Checkbox } from '@components/generic/form/Checkbox';
import { Input } from '@components/generic/form/Input';
import { IconButton } from '@components/generic/IconButton';
import { PrimaryTemplate } from '@components/templates/PrimaryTemplate';
import { connection } from '@core/connection';
import type { Protobuf } from '@meshtastic/meshtasticjs';
export interface WiFiProps {
@@ -23,7 +23,9 @@ export interface WiFiProps {
export const WiFi = ({ navOpen, setNavOpen }: WiFiProps): JSX.Element => {
const { t } = useTranslation();
const preferences = useAppSelector((state) => state.meshtastic.preferences);
const preferences = useAppSelector(
(state) => state.meshtastic.radio.preferences,
);
const [debug, setDebug] = React.useState(false);
const [loading, setLoading] = React.useState(false);
const { register, handleSubmit, formState, reset, control } =
@@ -37,6 +39,10 @@ export const WiFi = ({ navOpen, setNavOpen }: WiFiProps): JSX.Element => {
defaultValue: false,
});
React.useEffect(() => {
reset(preferences);
}, [reset, preferences]);
const onSubmit = handleSubmit((data) => {
setLoading(true);
void connection.setPreferences(data, async () => {