From 58de82b8d72d2f561a46262d9d9e3b1f8464d02f Mon Sep 17 00:00:00 2001 From: Sacha Weatherstone Date: Thu, 27 May 2021 09:05:45 +1000 Subject: [PATCH] WIP --- .eslintrc | 22 + package.json | 29 +- src/App.tsx | 71 +- src/Main.tsx | 14 +- src/components/ChatMessage.tsx | 19 +- src/components/Header.tsx | 76 +- src/components/MessageBox.tsx | 12 +- src/components/Sidebar.tsx | 6 +- src/components/Sidebar/Channels/Channel.tsx | 2 +- src/components/Sidebar/Channels/Index.tsx | 2 +- src/components/Sidebar/Device/Index.tsx | 10 +- src/components/Sidebar/Device/Settings.tsx | 50 +- src/components/Sidebar/Nodes/Index.tsx | 2 +- src/components/Sidebar/Nodes/Node.tsx | 2 +- src/components/Sidebar/UI/Index.tsx | 2 +- src/components/Sidebar/UI/Translations.tsx | 5 +- src/components/basic/ToggleSwitch.tsx | 3 +- src/components/logo.tsx | 2 +- src/index.tsx | 24 +- yarn-error.log | 3263 +++++++++++++++++++ yarn.lock | 1010 +++++- 21 files changed, 4449 insertions(+), 177 deletions(-) create mode 100644 .eslintrc create mode 100644 yarn-error.log diff --git a/.eslintrc b/.eslintrc new file mode 100644 index 00000000..b6a3abf2 --- /dev/null +++ b/.eslintrc @@ -0,0 +1,22 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": ["@typescript-eslint"], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", + "plugin:react/recommended", + "plugin:import/recommended", + "plugin:import/typescript", + "plugin:prettier/recommended" + ], + "rules": { + "@typescript-eslint/consistent-type-imports": "error" + }, + "settings": { + "react": { + "version": "detect" + } + } +} diff --git a/package.json b/package.json index bb4105ba..be43568c 100644 --- a/package.json +++ b/package.json @@ -7,36 +7,45 @@ "start": "NODE_ENV=development snowpack dev", "build": "snowpack build", "package": "yarn gzipper c -i html,js,css build build/output", - "format": "prettier --write \"src/**/*.{js,jsx,ts,tsx}\"", - "lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\"" + "format": "prettier --write 'src/**/*.{ts,tsx}'", + "lint": "eslint 'src/**/*.{ts,tsx}'" }, "dependencies": { "@headlessui/react": "^1.2.0", "@heroicons/react": "^1.0.1", "@meshtastic/meshtasticjs": "^0.6.12", "observable-hooks": "^4.0.3", - "react": "^17.0.0", - "react-dom": "^17.0.0", + "react": "^0.0.0-experimental-132b72d7b", + "react-dom": "^0.0.0-experimental-132b72d7b", "react-flags-select": "^2.1.2", - "react-hook-form": "^7.5.2", + "react-hook-form": "^7.6.5", "react-json-pretty": "^2.2.0", "rxjs": "^7.0.1", "yarn": "^1.22.10" }, "devDependencies": { "@snowpack/plugin-dotenv": "^2.0.5", - "@snowpack/plugin-postcss": "^1.2.2", + "@snowpack/plugin-postcss": "^1.4.0", "@snowpack/plugin-react-refresh": "^2.5.0", "@snowpack/plugin-typescript": "^1.2.0", - "@types/react": "^17.0.5", - "@types/react-dom": "^17.0.4", + "@types/eslint": "^7.2.11", + "@types/react": "^17.0.6", + "@types/react-dom": "^17.0.5", "@types/snowpack-env": "^2.3.2", + "@typescript-eslint/eslint-plugin": "^4.24.0", + "@typescript-eslint/parser": "^4.24.0", "autoprefixer": "^10.2.5", + "eslint": "^7.27.0", + "eslint-config-prettier": "^8.3.0", + "eslint-plugin-import": "^2.23.3", + "eslint-plugin-prettier": "^3.4.0", + "eslint-plugin-react": "^7.23.2", + "eslint-plugin-react-hooks": "^4.2.0", "gzipper": "^4.5.0", - "postcss": "^8.2.15", + "postcss": "^8.3.0", "postcss-cli": "^8.3.1", "prettier": "^2.3.0", - "snowpack": "^3.3.7", + "snowpack": "^3.5.1", "tailwindcss": "^2.1.2", "typescript": "^4.2.4" } diff --git a/src/App.tsx b/src/App.tsx index 4c3f2342..77d4c499 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,8 +1,12 @@ import React from 'react'; +import type { + IBLEConnection, + IHTTPConnection, + ISerialConnection, +} from '@meshtastic/meshtasticjs'; import { Client, - IHTTPConnection, Protobuf, SettingsManager, Types, @@ -36,33 +40,27 @@ export interface languageTemplate { no_message_placeholder: string; } -const App = () => { - const [ - deviceStatus, - setDeviceStatus, - ] = React.useState( - Types.DeviceStatusEnum.DEVICE_DISCONNECTED, - ); +const App = (): JSX.Element => { + const [deviceStatus, setDeviceStatus] = + React.useState( + Types.DeviceStatusEnum.DEVICE_DISCONNECTED, + ); const [myNodeInfo, setMyNodeInfo] = React.useState( Protobuf.MyNodeInfo.create(), ); const [channels, setChannels] = React.useState([] as Protobuf.Channel[]); const [nodes, setNodes] = React.useState([]); - const [connection, setConnection] = React.useState( - new IHTTPConnection(), - ); + const [connection, setConnection] = + React.useState(); const [isReady, setIsReady] = React.useState(false); - const [ - lastMeshInterraction, - setLastMeshInterraction, - ] = React.useState(0); + const [lastMeshInterraction, setLastMeshInterraction] = + React.useState(0); const [language, setLanguage] = React.useState( LanguageEnum.ENGLISH, ); - const [translations, setTranslations] = React.useState( - Translations_English, - ); + const [translations, setTranslations] = + React.useState(Translations_English); const [darkmode, setDarkmode] = React.useState(false); React.useEffect(() => { @@ -97,8 +95,12 @@ const App = () => { }); setConnection(connection); SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE; + }, []); - const deviceStatusEvent = connection.onDeviceStatusEvent.subscribe( + React.useEffect(() => { + console.log('UPDATING'); + + const deviceStatusEvent = connection?.onDeviceStatusEvent.subscribe( (status) => { setDeviceStatus(status); if (status === Types.DeviceStatusEnum.DEVICE_CONFIGURED) { @@ -106,11 +108,10 @@ const App = () => { } }, ); - const myNodeInfoEvent = connection.onMyNodeInfoEvent.subscribe( - setMyNodeInfo, - ); + const myNodeInfoEvent = + connection?.onMyNodeInfoEvent.subscribe(setMyNodeInfo); - const nodeInfoPacketEvent = connection.onNodeInfoPacketEvent.subscribe( + const nodeInfoPacketEvent = connection?.onNodeInfoPacketEvent.subscribe( (node) => { if ( nodes.findIndex( @@ -128,34 +129,34 @@ const App = () => { }, ); - const adminPacketEvent = connection.onAdminPacketEvent.subscribe( + const adminPacketEvent = connection?.onAdminPacketEvent.subscribe( (adminMessage) => { switch (adminMessage.data.variant.oneofKind) { case 'getChannelResponse': if (adminMessage.data.variant.getChannelResponse) { - let message = adminMessage.data.variant.getChannelResponse; + const message = adminMessage.data.variant.getChannelResponse; setChannels((channels) => [...channels, message]); } - + break; default: break; } }, ); - const meshHeartbeat = connection.onMeshHeartbeat.subscribe( + const meshHeartbeat = connection?.onMeshHeartbeat.subscribe( setLastMeshInterraction, ); return () => { - deviceStatusEvent.unsubscribe(); - myNodeInfoEvent.unsubscribe(); - nodeInfoPacketEvent.unsubscribe(); - adminPacketEvent.unsubscribe(); - meshHeartbeat.unsubscribe(); - connection.disconnect(); + deviceStatusEvent?.unsubscribe(); + myNodeInfoEvent?.unsubscribe(); + nodeInfoPacketEvent?.unsubscribe(); + adminPacketEvent?.unsubscribe(); + meshHeartbeat?.unsubscribe(); + connection?.disconnect(); }; - }, []); + }, [connection, nodes]); return (
@@ -163,6 +164,8 @@ const App = () => { status={deviceStatus} IsReady={isReady} LastMeshInterraction={lastMeshInterraction} + connection={connection} + setConnection={setConnection} />
>; } -const Main = (props: MainProps) => { +const Main = (props: MainProps): JSX.Element => { const [messages, setMessages] = React.useState< { message: Types.TextPacket; ack: boolean }[] >([]); const [sidebarOpen, setSidebarOpen] = useState(false); React.useEffect(() => { - const textPacketEvent = props.connection.onTextPacketEvent.subscribe( + const textPacketEvent = props.connection?.onTextPacketEvent.subscribe( (message) => { setMessages((messages) => [ ...messages, @@ -39,11 +41,11 @@ const Main = (props: MainProps) => { ]); }, ); - return () => textPacketEvent.unsubscribe(); + return () => textPacketEvent?.unsubscribe(); }, [props.connection]); React.useEffect(() => { - const routingPacketEvent = props.connection.onRoutingPacketEvent.subscribe( + const routingPacketEvent = props.connection?.onRoutingPacketEvent.subscribe( (routingPacket) => { setMessages( messages.map((message) => { @@ -60,7 +62,7 @@ const Main = (props: MainProps) => { ); }, ); - return () => routingPacketEvent.unsubscribe(); + return () => routingPacketEvent?.unsubscribe(); }, [props.connection, messages]); return ( diff --git a/src/components/ChatMessage.tsx b/src/components/ChatMessage.tsx index b6ca3035..2dcc83ad 100644 --- a/src/components/ChatMessage.tsx +++ b/src/components/ChatMessage.tsx @@ -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(); + + React.useEffect(() => { + setNode( + props.nodes.find( + (node) => node.data.num === props.message.message.packet.from, + ), + ); + }, [props.nodes, props.message]); return (
{ >
- {/* { - props.nodes.find( - (node) => node.data.num === props.message.message.packet.from, - ).data.user.longName - } */} + {node?.data.user?.longName ?? 'UNK'}

-

diff --git a/src/components/Header.tsx b/src/components/Header.tsx index b3b81a67..35817f1e 100644 --- a/src/components/Header.tsx +++ b/src/components/Header.tsx @@ -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 (