This commit is contained in:
Sacha Weatherstone
2021-05-27 09:05:45 +10:00
parent e172382765
commit 58de82b8d7
21 changed files with 4451 additions and 179 deletions
+12 -7
View File
@@ -1,4 +1,4 @@
import React from 'react';
import React, { useState } from 'react';
import {
CheckCircleIcon,
@@ -13,7 +13,16 @@ interface ChatMessageProps {
nodes: Types.NodeInfoPacket[];
}
const ChatMessage = (props: ChatMessageProps) => {
const ChatMessage = (props: ChatMessageProps): JSX.Element => {
const [node, setNode] = useState<Types.NodeInfoPacket>();
React.useEffect(() => {
setNode(
props.nodes.find(
(node) => node.data.num === props.message.message.packet.from,
),
);
}, [props.nodes, props.message]);
return (
<div className="flex items-end">
<div
@@ -35,11 +44,7 @@ const ChatMessage = (props: ChatMessageProps) => {
>
<div className="flex text-xs text-gray-500 space-x-1">
<div className="font-medium">
{/* {
props.nodes.find(
(node) => node.data.num === props.message.message.packet.from,
).data.user.longName
} */}
{node?.data.user?.longName ?? 'UNK'}
</div>
<p>-</p>
<div className="underline">
+71 -5
View File
@@ -1,11 +1,19 @@
import React from 'react';
import {
ChipIcon,
DeviceMobileIcon,
RssIcon,
StatusOfflineIcon,
StatusOnlineIcon,
WifiIcon,
} from '@heroicons/react/outline';
import { Types } from '@meshtastic/meshtasticjs';
import {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
Types,
} from '@meshtastic/meshtasticjs';
import Logo from './logo';
@@ -13,17 +21,75 @@ interface HeaderProps {
status: Types.DeviceStatusEnum;
IsReady: boolean;
LastMeshInterraction: number;
connection?: IHTTPConnection | ISerialConnection | IBLEConnection;
setConnection: React.Dispatch<
React.SetStateAction<
IHTTPConnection | ISerialConnection | IBLEConnection | undefined
>
>;
}
const Header = (props: HeaderProps) => {
const Header = (props: HeaderProps): JSX.Element => {
const [activeConnection, setActiveConnection] =
React.useState<'http' | 'serial' | 'ble'>('http');
return (
<nav className="w-full shadow-md">
<div className="flex w-full container mx-auto justify-between px-6 py-4">
<Logo />
<div></div>
<div className="flex items-center">
<div className="flex pl-4">
<div className="flex space-x-2 items-center">
<button
className={`rounded-md px-3 py-2 ${
activeConnection === 'serial' ? 'bg-green-300' : 'bg-gray-300'
}`}
onClick={() => {
props.connection?.disconnect();
const connection = new ISerialConnection();
connection.connect({});
setActiveConnection('serial');
props.setConnection(connection);
}}
>
<ChipIcon className="m-auto h-5 w-5" />
</button>
<button
className={`rounded-md px-3 py-2 ${
activeConnection === 'http' ? 'bg-green-300' : 'bg-gray-300'
}`}
onClick={() => {
props.connection?.disconnect();
const connection = new IHTTPConnection();
connection.connect({
address:
import.meta.env.NODE_ENV === 'production'
? window.location.hostname
: import.meta.env.SNOWPACK_PUBLIC_DEVICE_IP,
receiveBatchRequests: false,
tls: false,
fetchInterval: 2000,
});
setActiveConnection('http');
props.setConnection(connection);
}}
>
<WifiIcon className="m-auto h-5 w-5" />
</button>
<button
className={`rounded-md px-3 py-2 ${
activeConnection === 'ble' ? 'bg-green-300' : 'bg-gray-300'
}`}
onClick={() => {
props.connection?.disconnect();
const connection = new IBLEConnection();
connection.connect({});
setActiveConnection('ble');
props.setConnection(connection);
}}
>
<RssIcon className="m-auto h-5 w-5" />
</button>
<div className="flex pl-2">
<div
className={`w-5 h-5 rounded-full ${
new Date(props.LastMeshInterraction) <
@@ -43,7 +109,7 @@ const Header = (props: HeaderProps) => {
)}
</div>
<div className="flex pl-4">
<div className="flex pl-2">
<div
className={`w-5 h-5 rounded-full ${
props.status <= Types.DeviceStatusEnum.DEVICE_DISCONNECTED
+8 -4
View File
@@ -1,7 +1,11 @@
import React from 'react';
import { MenuIcon, PaperAirplaneIcon } from '@heroicons/react/outline';
import type { IHTTPConnection } from '@meshtastic/meshtasticjs';
import type {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
} from '@meshtastic/meshtasticjs';
import type { languageTemplate } from '../App';
@@ -9,15 +13,15 @@ export interface MessageBoxProps {
translations: languageTemplate;
sidebarOpen: boolean;
setSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>;
connection: IHTTPConnection;
connection?: ISerialConnection | IHTTPConnection | IBLEConnection;
isReady: boolean;
}
const MessageBox = (props: MessageBoxProps) => {
const MessageBox = (props: MessageBoxProps): JSX.Element => {
const [currentMessage, setCurrentMessage] = React.useState('');
const sendMessage = () => {
if (props.isReady) {
props.connection.sendText(currentMessage, undefined, true);
props.connection?.sendText(currentMessage, undefined, true);
setCurrentMessage('');
}
};
+4 -2
View File
@@ -1,7 +1,9 @@
import React from 'react';
import type {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
Protobuf,
Types,
} from '@meshtastic/meshtasticjs';
@@ -16,7 +18,7 @@ interface SidebarProps {
isReady: boolean;
nodes: Types.NodeInfoPacket[];
channels: Protobuf.Channel[];
connection: IHTTPConnection;
connection?: ISerialConnection | IHTTPConnection | IBLEConnection;
language: LanguageEnum;
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
translations: languageTemplate;
@@ -26,7 +28,7 @@ interface SidebarProps {
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
}
const Sidebar = (props: SidebarProps) => {
const Sidebar = (props: SidebarProps): JSX.Element => {
return (
<div
className={`${
+1 -1
View File
@@ -8,7 +8,7 @@ export interface ChannelProps {
channel: Protobuf.Channel;
}
const Channel = (props: ChannelProps) => {
const Channel = (props: ChannelProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+1 -1
View File
@@ -17,7 +17,7 @@ export interface ChannelsProps {
translations: languageTemplate;
}
const Channels = (props: ChannelsProps) => {
const Channels = (props: ChannelsProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+7 -3
View File
@@ -6,18 +6,22 @@ import {
ChevronDownIcon,
ChevronRightIcon,
} from '@heroicons/react/outline';
import type { IHTTPConnection } from '@meshtastic/meshtasticjs';
import type {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
} from '@meshtastic/meshtasticjs';
import type { languageTemplate } from '../../../App';
import Settings from './Settings';
interface DeviceProps {
isReady: boolean;
connection: IHTTPConnection;
connection?: ISerialConnection | IHTTPConnection | IBLEConnection;
translations: languageTemplate;
}
const Device = (props: DeviceProps) => {
const Device = (props: DeviceProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+19 -31
View File
@@ -1,27 +1,27 @@
import React from 'react';
import { ObservableResource, useObservableSuspense } from 'observable-hooks';
import { useForm } from 'react-hook-form';
import JSONPretty from 'react-json-pretty';
import type { languageTemplate } from 'src/App';
import { SaveIcon } from '@heroicons/react/outline';
import { IHTTPConnection, Protobuf } from '@meshtastic/meshtasticjs';
import type {
IBLEConnection,
IHTTPConnection,
ISerialConnection,
} from '@meshtastic/meshtasticjs';
import { Protobuf } from '@meshtastic/meshtasticjs';
import type { languageTemplate } from '../../../../src/App';
export interface SettingsProps {
isReady: boolean;
connection: IHTTPConnection;
connection?: ISerialConnection | IHTTPConnection | IBLEConnection;
translations: languageTemplate;
}
const Settings = (props: SettingsProps) => {
const Settings = (props: SettingsProps): JSX.Element => {
React.useEffect(() => {
const a = useObservableSuspense(
new ObservableResource(
props.connection.onAdminPacketEvent.asObservable(),
),
);
const adminPacketEvent = props.connection.onAdminPacketEvent.subscribe(
const adminPacketEvent = props.connection?.onAdminPacketEvent.subscribe(
(adminMessage) => {
switch (adminMessage.data.variant.oneofKind) {
case 'getRadioResponse':
@@ -34,35 +34,23 @@ const Settings = (props: SettingsProps) => {
},
);
return () => adminPacketEvent.unsubscribe();
return () => adminPacketEvent?.unsubscribe();
}, []);
const [
preferences,
setPreferences,
] = React.useState<Protobuf.RadioConfig_UserPreferences>();
const {
register,
setValue,
handleSubmit,
formState: { errors },
} = useForm<Protobuf.RadioConfig_UserPreferences>({
defaultValues: preferences,
});
const [preferences, setPreferences] =
React.useState<Protobuf.RadioConfig_UserPreferences>();
const { register, handleSubmit } =
useForm<Protobuf.RadioConfig_UserPreferences>({
defaultValues: preferences,
});
const onSubmit = handleSubmit((data) => console.log(data));
return (
<form onSubmit={onSubmit}>
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
<div className="my-auto">{props.translations.device_region_title}</div>
<div className="flex shadow-md rounded-md ml-2">
<select
value={preferences.region ?? Protobuf.RegionCode.Unset}
// onChange={(e) => {
// preferences.region = parseInt(e.target.value);
// }}
>
<select value={preferences?.region ?? Protobuf.RegionCode.Unset}>
<option value={Protobuf.RegionCode.ANZ}>
{Protobuf.RegionCode[Protobuf.RegionCode.ANZ]}
</option>
+1 -1
View File
@@ -18,7 +18,7 @@ interface NodesProps {
myId: number;
}
const Nodes = (props: NodesProps) => {
const Nodes = (props: NodesProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+1 -1
View File
@@ -17,7 +17,7 @@ export interface NodeProps {
myId: number;
}
const Node = (props: NodeProps) => {
const Node = (props: NodeProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+1 -1
View File
@@ -18,7 +18,7 @@ interface UIProps {
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
}
const UI = (props: UIProps) => {
const UI = (props: UIProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+3 -2
View File
@@ -5,7 +5,8 @@ import { Br, Jp, Us } from 'react-flags-select';
import { Disclosure } from '@headlessui/react';
import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/outline';
import { LanguageEnum, languageTemplate } from '../../../App';
import type { languageTemplate } from '../../../App';
import { LanguageEnum } from '../../../App';
export interface TranslationsProps {
language: LanguageEnum;
@@ -13,7 +14,7 @@ export interface TranslationsProps {
translations: languageTemplate;
}
const Translations = (props: TranslationsProps) => {
const Translations = (props: TranslationsProps): JSX.Element => {
return (
<Disclosure>
{({ open }) => (
+1 -2
View File
@@ -4,10 +4,9 @@ import { Switch } from '@headlessui/react';
interface ToggleSwitchProps {
active: boolean;
toggle?: Function;
}
const ToggleSwitch = (props: ToggleSwitchProps) => {
const ToggleSwitch = (props: ToggleSwitchProps): JSX.Element => {
const [active, setActive] = React.useState(false);
React.useEffect(() => {
+1 -1
View File
@@ -1,6 +1,6 @@
import React from 'react';
const Logo = () => {
const Logo = (): JSX.Element => {
return (
<svg
height="30"