mirror of
https://github.com/meshtastic/web.git
synced 2026-05-19 11:45:17 -04:00
COnnection modal fix & notification basics
This commit is contained in:
@@ -1 +1,2 @@
|
||||
VITE_PUBLIC_DEVICE_IP=
|
||||
VITE_PUBLIC_DEVICE_IP=
|
||||
VITE_PUBLIC_HOSTED=
|
||||
@@ -14,7 +14,7 @@
|
||||
"dependencies": {
|
||||
"@headlessui/react": "^1.4.2",
|
||||
"@meshtastic/meshtasticjs": "^0.6.35",
|
||||
"@reduxjs/toolkit": "^1.7.0",
|
||||
"@reduxjs/toolkit": "^1.7.1",
|
||||
"base64-js": "^1.5.1",
|
||||
"boring-avatars": "^1.5.8",
|
||||
"i18next": "^21.6.0",
|
||||
@@ -31,7 +31,7 @@
|
||||
"react-redux": "^7.2.6",
|
||||
"react-select": "^5.2.1",
|
||||
"rfc4648": "^1.5.0",
|
||||
"swr": "^1.1.1",
|
||||
"swr": "^1.1.2-beta.0",
|
||||
"timeago-react": "^3.0.4",
|
||||
"type-route": "^0.6.0",
|
||||
"use-breakpoint": "^3.0.0"
|
||||
@@ -60,12 +60,12 @@
|
||||
"gzipper": "^6.0.0",
|
||||
"postcss": "^8.4.5",
|
||||
"prettier": "^2.5.1",
|
||||
"tailwindcss": "^3.0.2",
|
||||
"tailwindcss": "^3.0.5",
|
||||
"tar": "^6.1.11",
|
||||
"typescript": "^4.5.4",
|
||||
"vite": "^2.7.2",
|
||||
"vite-plugin-cdn-import": "^0.3.5",
|
||||
"vite-plugin-pwa": "^0.11.11",
|
||||
"vite-plugin-pwa": "^0.11.12",
|
||||
"workbox-window": "^6.4.2"
|
||||
}
|
||||
}
|
||||
|
||||
62
pnpm-lock.yaml
generated
62
pnpm-lock.yaml
generated
@@ -3,7 +3,7 @@ lockfileVersion: 5.3
|
||||
specifiers:
|
||||
'@headlessui/react': ^1.4.2
|
||||
'@meshtastic/meshtasticjs': ^0.6.35
|
||||
'@reduxjs/toolkit': ^1.7.0
|
||||
'@reduxjs/toolkit': ^1.7.1
|
||||
'@types/mapbox-gl': ^2.6.0
|
||||
'@types/react': ^17.0.37
|
||||
'@types/react-dom': ^17.0.11
|
||||
@@ -43,8 +43,8 @@ specifiers:
|
||||
react-redux: ^7.2.6
|
||||
react-select: ^5.2.1
|
||||
rfc4648: ^1.5.0
|
||||
swr: ^1.1.1
|
||||
tailwindcss: ^3.0.2
|
||||
swr: ^1.1.2-beta.0
|
||||
tailwindcss: ^3.0.5
|
||||
tar: ^6.1.11
|
||||
timeago-react: ^3.0.4
|
||||
type-route: ^0.6.0
|
||||
@@ -52,13 +52,13 @@ specifiers:
|
||||
use-breakpoint: ^3.0.0
|
||||
vite: ^2.7.2
|
||||
vite-plugin-cdn-import: ^0.3.5
|
||||
vite-plugin-pwa: ^0.11.11
|
||||
vite-plugin-pwa: ^0.11.12
|
||||
workbox-window: ^6.4.2
|
||||
|
||||
dependencies:
|
||||
'@headlessui/react': 1.4.2_react-dom@17.0.2+react@17.0.2
|
||||
'@meshtastic/meshtasticjs': 0.6.35
|
||||
'@reduxjs/toolkit': 1.7.0_react-redux@7.2.6+react@17.0.2
|
||||
'@reduxjs/toolkit': 1.7.1_react-redux@7.2.6+react@17.0.2
|
||||
base64-js: 1.5.1
|
||||
boring-avatars: 1.5.8
|
||||
i18next: 21.6.0
|
||||
@@ -75,7 +75,7 @@ dependencies:
|
||||
react-redux: 7.2.6_react-dom@17.0.2+react@17.0.2
|
||||
react-select: 5.2.1_5539cae010396b202b015f3568914e95
|
||||
rfc4648: 1.5.0
|
||||
swr: 1.1.1_react@17.0.2
|
||||
swr: 1.1.2-beta.0_react@17.0.2
|
||||
timeago-react: 3.0.4_react@17.0.2
|
||||
type-route: 0.6.0
|
||||
use-breakpoint: 3.0.0_react-dom@17.0.2+react@17.0.2
|
||||
@@ -104,12 +104,12 @@ devDependencies:
|
||||
gzipper: 6.0.0
|
||||
postcss: 8.4.5
|
||||
prettier: 2.5.1
|
||||
tailwindcss: 3.0.2_16a290f6d0e3717bf6d2667234aebd30
|
||||
tailwindcss: 3.0.5_16a290f6d0e3717bf6d2667234aebd30
|
||||
tar: 6.1.11
|
||||
typescript: 4.5.4
|
||||
vite: 2.7.2
|
||||
vite-plugin-cdn-import: 0.3.5
|
||||
vite-plugin-pwa: 0.11.11_vite@2.7.2
|
||||
vite-plugin-pwa: 0.11.12_vite@2.7.2
|
||||
workbox-window: 6.4.2
|
||||
|
||||
packages:
|
||||
@@ -1249,7 +1249,7 @@ packages:
|
||||
babel-plugin-polyfill-corejs2: 0.3.0_@babel+core@7.16.5
|
||||
babel-plugin-polyfill-corejs3: 0.4.0_@babel+core@7.16.5
|
||||
babel-plugin-polyfill-regenerator: 0.3.0_@babel+core@7.16.5
|
||||
core-js-compat: 3.19.3
|
||||
core-js-compat: 3.20.0
|
||||
semver: 6.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
@@ -1523,8 +1523,8 @@ packages:
|
||||
resolution: {integrity: sha512-HZwkgJW9SGiE9+0lWKr1X997tmG01/40j+hr9yBVk+hTQcm7Hsf77XhMNtsDjWUOcspG6GBXu8o3g4i3kD5/zQ==}
|
||||
dev: false
|
||||
|
||||
/@reduxjs/toolkit/1.7.0_react-redux@7.2.6+react@17.0.2:
|
||||
resolution: {integrity: sha512-iApo4zS+8kWnIn4xucTDWpqRjDNkXruFIyJQWwThIEIbMj5kwqvbMaQcEgd2a305B68Z+4bvZqAqJSATeddaJA==}
|
||||
/@reduxjs/toolkit/1.7.1_react-redux@7.2.6+react@17.0.2:
|
||||
resolution: {integrity: sha512-wXwXYjBVz/ItxB7SMzEAMmEE/FBiY1ze18N+VVVX7NtVbRUrdOGKhpQMHivIJfkbJvSdLUU923a/yAagJQzY0Q==}
|
||||
peerDependencies:
|
||||
react: ^16.9.0 || ^17.0.0 || 18.0.0-beta
|
||||
react-redux: ^7.2.1 || ^8.0.0-beta
|
||||
@@ -1646,8 +1646,8 @@ packages:
|
||||
'@types/geojson': 7946.0.8
|
||||
dev: true
|
||||
|
||||
/@types/node/16.11.13:
|
||||
resolution: {integrity: sha512-eUXZzHLHoZqj1frtUetNkUetYoJ6X55UmrVnFD4DMhVeAmwLjniZhtBmsRiemQh4uq4G3vUra/Ws/hs9vEvL3Q==}
|
||||
/@types/node/17.0.0:
|
||||
resolution: {integrity: sha512-eMhwJXc931Ihh4tkU+Y7GiLzT/y/DBNpNtr4yU9O2w3SYBsr9NaOPhQlLKRmoWtI54uNwuo0IOUFQjVOTZYRvw==}
|
||||
dev: true
|
||||
|
||||
/@types/parse-json/4.0.0:
|
||||
@@ -1694,7 +1694,7 @@ packages:
|
||||
/@types/resolve/1.17.1:
|
||||
resolution: {integrity: sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==}
|
||||
dependencies:
|
||||
'@types/node': 16.11.13
|
||||
'@types/node': 17.0.0
|
||||
dev: true
|
||||
|
||||
/@types/scheduler/0.16.2:
|
||||
@@ -2121,7 +2121,7 @@ packages:
|
||||
postcss: ^8.1.0
|
||||
dependencies:
|
||||
browserslist: 4.19.1
|
||||
caniuse-lite: 1.0.30001286
|
||||
caniuse-lite: 1.0.30001287
|
||||
fraction.js: 4.1.2
|
||||
normalize-range: 0.1.2
|
||||
picocolors: 1.0.0
|
||||
@@ -2171,7 +2171,7 @@ packages:
|
||||
dependencies:
|
||||
'@babel/core': 7.16.5
|
||||
'@babel/helper-define-polyfill-provider': 0.3.0_@babel+core@7.16.5
|
||||
core-js-compat: 3.19.3
|
||||
core-js-compat: 3.20.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
dev: true
|
||||
@@ -2223,8 +2223,8 @@ packages:
|
||||
engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
caniuse-lite: 1.0.30001286
|
||||
electron-to-chromium: 1.4.18
|
||||
caniuse-lite: 1.0.30001287
|
||||
electron-to-chromium: 1.4.20
|
||||
escalade: 3.1.1
|
||||
node-releases: 2.0.1
|
||||
picocolors: 1.0.0
|
||||
@@ -2256,8 +2256,8 @@ packages:
|
||||
engines: {node: '>= 6'}
|
||||
dev: true
|
||||
|
||||
/caniuse-lite/1.0.30001286:
|
||||
resolution: {integrity: sha512-zaEMRH6xg8ESMi2eQ3R4eZ5qw/hJiVsO/HlLwniIwErij0JDr9P+8V4dtx1l+kLq6j3yy8l8W4fst1lBnat5wQ==}
|
||||
/caniuse-lite/1.0.30001287:
|
||||
resolution: {integrity: sha512-4udbs9bc0hfNrcje++AxBuc6PfLNHwh3PO9kbwnfCQWyqtlzg3py0YgFu8jyRTTo85VAz4U+VLxSlID09vNtWA==}
|
||||
dev: true
|
||||
|
||||
/chalk/2.4.2:
|
||||
@@ -2342,8 +2342,8 @@ packages:
|
||||
safe-buffer: 5.1.2
|
||||
dev: true
|
||||
|
||||
/core-js-compat/3.19.3:
|
||||
resolution: {integrity: sha512-59tYzuWgEEVU9r+SRgceIGXSSUn47JknoiXW6Oq7RW8QHjXWz3/vp8pa7dbtuVu40sewz3OP3JmQEcDdztrLhA==}
|
||||
/core-js-compat/3.20.0:
|
||||
resolution: {integrity: sha512-relrah5h+sslXssTTOkvqcC/6RURifB0W5yhYBdBkaPYa5/2KBMiog3XiD+s3TwEHWxInWVv4Jx2/Lw0vng+IQ==}
|
||||
dependencies:
|
||||
browserslist: 4.19.1
|
||||
semver: 7.0.0
|
||||
@@ -2509,8 +2509,8 @@ packages:
|
||||
jake: 10.8.2
|
||||
dev: true
|
||||
|
||||
/electron-to-chromium/1.4.18:
|
||||
resolution: {integrity: sha512-i7nKjGGBE1+YUIbfLObA1EZPmN7J1ITEllbhusDk+KIk6V6gUxN9PFe36v+Sd+8Cg0k3cgUv9lQhQZalr8rggw==}
|
||||
/electron-to-chromium/1.4.20:
|
||||
resolution: {integrity: sha512-N7ZVNrdzX8NE90OXEFBMsBf3fp8P/vVDUER3WCUZjzC7OkNTXHVoF6W9qVhq8+dA8tGnbDajzUpj2ISNVVyj+Q==}
|
||||
dev: true
|
||||
|
||||
/emoji-regex/8.0.0:
|
||||
@@ -3730,7 +3730,7 @@ packages:
|
||||
resolution: {integrity: sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==}
|
||||
engines: {node: '>= 10.13.0'}
|
||||
dependencies:
|
||||
'@types/node': 16.11.13
|
||||
'@types/node': 17.0.0
|
||||
merge-stream: 2.0.0
|
||||
supports-color: 7.2.0
|
||||
dev: true
|
||||
@@ -4885,8 +4885,8 @@ packages:
|
||||
has-flag: 4.0.0
|
||||
dev: true
|
||||
|
||||
/swr/1.1.1_react@17.0.2:
|
||||
resolution: {integrity: sha512-ZpUHyU3N3snj2QGFeE2Fd3BXl1CVS6YQIQGb1ttPAkTmvwZqDyV3GRMNPsaeAYCBM74tfn4XbKx28FVQR0mS7Q==}
|
||||
/swr/1.1.2-beta.0_react@17.0.2:
|
||||
resolution: {integrity: sha512-e7ZcPCrEvGX+s4jDtBwV9c+HKqHzG1secuwU8bYjnnGkSJMneyn7OaabJKtRh922DH5a3k2vvBdhftoSL8bHJQ==}
|
||||
peerDependencies:
|
||||
react: ^16.11.0 || ^17.0.0 || ^18.0.0
|
||||
dependencies:
|
||||
@@ -4904,8 +4904,8 @@ packages:
|
||||
strip-ansi: 6.0.1
|
||||
dev: true
|
||||
|
||||
/tailwindcss/3.0.2_16a290f6d0e3717bf6d2667234aebd30:
|
||||
resolution: {integrity: sha512-i1KpjYnGYftjzdAth6jA5iMPjhxpUkk5L6DafhfnQs+KiiWaThYxmk47Weh4oFH1mZqP6MuiQNHxtoRVPOraLg==}
|
||||
/tailwindcss/3.0.5_16a290f6d0e3717bf6d2667234aebd30:
|
||||
resolution: {integrity: sha512-59pNgzx2o+wkAk7IZGIH7H9eNS53gzZGrO3+NPyOEWHDbquHgiLL/c993T5t1vPSAeBxox4X5OgZwNuRvXVf+g==}
|
||||
engines: {node: '>=12.13.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -5170,8 +5170,8 @@ packages:
|
||||
- rollup
|
||||
dev: true
|
||||
|
||||
/vite-plugin-pwa/0.11.11_vite@2.7.2:
|
||||
resolution: {integrity: sha512-/nSLS7VfGN5UrL4a1ALGEQAyga/H0hYZjEkwPehiEFW1PM1DTi1A8GkPCsmevKwR6vt10P+5wS1wrvSgwQemzw==}
|
||||
/vite-plugin-pwa/0.11.12_vite@2.7.2:
|
||||
resolution: {integrity: sha512-XqFmA4y9C4RBb5osSsa26GVwOSwbzf2GNVcT5+06KYYdguqLpuI9FW7iV/akZqg0OUNUpH4tHfme8SnHA4PIXA==}
|
||||
peerDependencies:
|
||||
vite: ^2.0.0
|
||||
dependencies:
|
||||
|
||||
14
src/App.tsx
14
src/App.tsx
@@ -1,4 +1,4 @@
|
||||
import type React from 'react';
|
||||
import React from 'react';
|
||||
|
||||
import { DeviceStatus } from '@app/components/menu/buttons/DeviceStatus';
|
||||
import { useAppSelector } from '@app/hooks/redux';
|
||||
@@ -9,17 +9,23 @@ import { Logo } from '@components/menu/Logo';
|
||||
import { MobileNav } from '@components/menu/MobileNav';
|
||||
import { Navigation } from '@components/menu/Navigation';
|
||||
import { useRoute } from '@core/router';
|
||||
import { requestNotificationPermission } from '@core/utils/notifications';
|
||||
import { Messages } from '@pages/Messages';
|
||||
import { Nodes } from '@pages/Nodes/Index';
|
||||
import { NotFound } from '@pages/NotFound';
|
||||
import { Plugins } from '@pages/Plugins/Index';
|
||||
import { Settings } from '@pages/settings/Index';
|
||||
|
||||
import { NotFound } from './pages/NotFound';
|
||||
import { Plugins } from './pages/Plugins/Index';
|
||||
|
||||
export const App = (): JSX.Element => {
|
||||
const route = useRoute();
|
||||
const darkMode = useAppSelector((state) => state.app.darkMode);
|
||||
|
||||
React.useEffect(() => {
|
||||
requestNotificationPermission().catch((e) => {
|
||||
console.log(e);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div className={`h-screen w-screen ${darkMode ? 'dark' : ''}`}>
|
||||
<Connection />
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useAppDispatch, useAppSelector } from '@app/hooks/redux';
|
||||
import { BLE } from '@components/connection/BLE';
|
||||
import { HTTP } from '@components/connection/HTTP';
|
||||
import { Serial } from '@components/connection/Serial';
|
||||
import { Button } from '@components/generic/Button';
|
||||
import { Card } from '@components/generic/Card';
|
||||
import { Select } from '@components/generic/form/Select';
|
||||
import { Modal } from '@components/generic/Modal';
|
||||
import { DeviceStatus } from '@components/menu/buttons/DeviceStatus';
|
||||
import { connection, connectionUrl, setConnection } from '@core/connection';
|
||||
import {
|
||||
closeConnectionModal,
|
||||
@@ -16,9 +17,6 @@ import {
|
||||
} from '@core/slices/appSlice';
|
||||
import { Types } from '@meshtastic/meshtasticjs';
|
||||
|
||||
import { BLE } from './connection/BLE';
|
||||
import { HTTP } from './connection/HTTP';
|
||||
|
||||
export const Connection = (): JSX.Element => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
@@ -58,23 +56,25 @@ export const Connection = (): JSX.Element => {
|
||||
>
|
||||
<Card>
|
||||
<div className="w-full max-w-3xl p-10">
|
||||
<div className="flex justify-between w-full border rounded-md">
|
||||
<div className="p-2">
|
||||
<DeviceStatus />
|
||||
{state.deviceStatus === Types.DeviceStatusEnum.DEVICE_DISCONNECTED ? (
|
||||
<div className="space-y-2">
|
||||
<Select
|
||||
label="Connection Method"
|
||||
optionsEnum={connType}
|
||||
value={appState.connType}
|
||||
onChange={(e): void => {
|
||||
dispatch(setConnType(parseInt(e.target.value)));
|
||||
}}
|
||||
/>
|
||||
{appState.connType === connType.HTTP && <HTTP />}
|
||||
{appState.connType === connType.BLE && <BLE />}
|
||||
{appState.connType === connType.SERIAL && <Serial />}
|
||||
</div>
|
||||
<div className="p-2 my-auto">
|
||||
) : (
|
||||
<div>
|
||||
<span>Connecting...</span>
|
||||
{state.deviceStatus ===
|
||||
Types.DeviceStatusEnum.DEVICE_DISCONNECTED ? (
|
||||
<Button
|
||||
padding={2}
|
||||
border
|
||||
onClick={async (): Promise<void> => {
|
||||
await setConnection(appState.connType);
|
||||
}}
|
||||
>
|
||||
Connect
|
||||
</Button>
|
||||
) : (
|
||||
Types.DeviceStatusEnum.DEVICE_CONNECTED && (
|
||||
<Button
|
||||
padding={2}
|
||||
border
|
||||
@@ -86,22 +86,6 @@ export const Connection = (): JSX.Element => {
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
{state.deviceStatus ===
|
||||
Types.DeviceStatusEnum.DEVICE_DISCONNECTED && (
|
||||
<form className="space-y-2">
|
||||
<Select
|
||||
label="Method"
|
||||
optionsEnum={connType}
|
||||
value={appState.connType}
|
||||
onChange={(e): void => {
|
||||
dispatch(setConnType(parseInt(e.target.value)));
|
||||
}}
|
||||
/>
|
||||
{appState.connType === connType.HTTP && <HTTP />}
|
||||
{appState.connType === connType.BLE && <BLE />}
|
||||
{appState.connType === connType.SERIAL && <Serial />}
|
||||
</form>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FiCheck } from 'react-icons/fi';
|
||||
|
||||
import { connType } from '@app/core/slices/appSlice';
|
||||
import { Button } from '@components/generic/Button';
|
||||
import { IconButton } from '@components/generic/IconButton';
|
||||
import { ble, setConnection } from '@core/connection';
|
||||
|
||||
export const BLE = (): JSX.Element => {
|
||||
const [bleDevices, setBleDevices] = React.useState<BluetoothDevice[]>([]);
|
||||
|
||||
const { register, handleSubmit, control } = useForm<{
|
||||
device?: BluetoothDevice;
|
||||
}>();
|
||||
|
||||
const updateBleDeviceList = React.useCallback(async (): Promise<void> => {
|
||||
const devices = await ble.getDevices();
|
||||
setBleDevices(devices);
|
||||
@@ -18,8 +24,12 @@ export const BLE = (): JSX.Element => {
|
||||
void updateBleDeviceList();
|
||||
}, [updateBleDeviceList]);
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
await setConnection(connType.BLE);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<form onSubmit={onSubmit} className="space-y-2">
|
||||
{bleDevices.map((device, index) => (
|
||||
<div
|
||||
onClick={async (): Promise<void> => {
|
||||
@@ -37,6 +47,9 @@ export const BLE = (): JSX.Element => {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Button type="submit" className="mt-2 ml-auto" border>
|
||||
Connect
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,17 +1,52 @@
|
||||
import React from 'react';
|
||||
import type React from 'react';
|
||||
|
||||
import { useForm, useWatch } from 'react-hook-form';
|
||||
|
||||
import { useAppDispatch } from '@app/hooks/redux.js';
|
||||
import { Button } from '@components/generic/Button';
|
||||
import { Checkbox } from '@components/generic/form/Checkbox';
|
||||
import { Input } from '@components/generic/form/Input';
|
||||
import { Select } from '@components/generic/form/Select';
|
||||
import { connectionUrl } from '@core/connection';
|
||||
import { connectionUrl, setConnection } from '@core/connection';
|
||||
import { connType, setConnectionParams } from '@core/slices/appSlice';
|
||||
|
||||
export const HTTP = (): JSX.Element => {
|
||||
const [httpIpSource, setHttpIpSource] = React.useState<'local' | 'remote'>(
|
||||
'local',
|
||||
);
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const { register, handleSubmit, control } = useForm<{
|
||||
ipSource: 'local' | 'remote';
|
||||
ip?: string;
|
||||
tls: boolean;
|
||||
}>({
|
||||
defaultValues: {
|
||||
ipSource: 'local',
|
||||
ip: connectionUrl,
|
||||
tls: false,
|
||||
},
|
||||
});
|
||||
|
||||
const watchIpSource = useWatch({
|
||||
control,
|
||||
name: 'ipSource',
|
||||
defaultValue: 'local',
|
||||
});
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
dispatch(
|
||||
setConnectionParams({
|
||||
type: connType.HTTP,
|
||||
params: {
|
||||
address: data.ip ?? connectionUrl,
|
||||
tls: data.tls,
|
||||
fetchInterval: 2000,
|
||||
},
|
||||
}),
|
||||
);
|
||||
await setConnection(connType.HTTP);
|
||||
});
|
||||
|
||||
return (
|
||||
<div>
|
||||
<form onSubmit={onSubmit}>
|
||||
<Select
|
||||
label="Host Source"
|
||||
options={[
|
||||
@@ -24,17 +59,17 @@ export const HTTP = (): JSX.Element => {
|
||||
value: 'remote',
|
||||
},
|
||||
]}
|
||||
value={httpIpSource}
|
||||
onChange={(e): void => {
|
||||
setHttpIpSource(e.target.value as 'local' | 'remote');
|
||||
}}
|
||||
{...register('ipSource')}
|
||||
/>
|
||||
{httpIpSource === 'local' ? (
|
||||
{watchIpSource === 'local' ? (
|
||||
<Input label="Host" value={connectionUrl} disabled />
|
||||
) : (
|
||||
<Input label="Host" />
|
||||
<Input label="Host" {...register('ip')} />
|
||||
)}
|
||||
<Checkbox label="Use TLS?" />
|
||||
</div>
|
||||
<Checkbox label="Use TLS?" {...register('tls')} />
|
||||
<Button type="submit" className="mt-2 ml-auto" border>
|
||||
Connect
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
|
||||
import { useForm } from 'react-hook-form';
|
||||
import { FiCheck } from 'react-icons/fi';
|
||||
|
||||
import { Button } from '@components/generic/Button';
|
||||
import { IconButton } from '@components/generic/IconButton';
|
||||
import { serial, setConnection } from '@core/connection';
|
||||
import { connType } from '@core/slices/appSlice';
|
||||
@@ -9,6 +11,10 @@ import { connType } from '@core/slices/appSlice';
|
||||
export const Serial = (): JSX.Element => {
|
||||
const [serialDevices, setSerialDevices] = React.useState<SerialPort[]>([]);
|
||||
|
||||
const { register, handleSubmit, control } = useForm<{
|
||||
device?: SerialPort;
|
||||
}>();
|
||||
|
||||
const updateSerialDeviceList = React.useCallback(async (): Promise<void> => {
|
||||
const devices = await serial.getPorts();
|
||||
setSerialDevices(devices);
|
||||
@@ -18,8 +24,12 @@ export const Serial = (): JSX.Element => {
|
||||
void updateSerialDeviceList();
|
||||
}, [updateSerialDeviceList]);
|
||||
|
||||
const onSubmit = handleSubmit(async (data) => {
|
||||
await setConnection(connType.SERIAL);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<form onSubmit={onSubmit} className="space-y-2">
|
||||
{serialDevices.map((device, index) => (
|
||||
<div
|
||||
className="flex justify-between p-2 bg-gray-700 rounded-md"
|
||||
@@ -41,6 +51,9 @@ export const Serial = (): JSX.Element => {
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Button type="submit" className="mt-2 ml-auto" border>
|
||||
Connect
|
||||
</Button>
|
||||
</form>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -23,6 +23,8 @@ import {
|
||||
Types,
|
||||
} from '@meshtastic/meshtasticjs';
|
||||
|
||||
import { showNotification } from './utils/notifications.js';
|
||||
|
||||
type connectionType = IBLEConnection | IHTTPConnection | ISerialConnection;
|
||||
|
||||
export let connection: connectionType = new IHTTPConnection();
|
||||
@@ -151,6 +153,7 @@ const registerListeners = (): void => {
|
||||
|
||||
connection.onTextPacket.subscribe((message) => {
|
||||
const myNodeNum = store.getState().meshtastic.radio.hardware.myNodeNum;
|
||||
showNotification('New message', message.data);
|
||||
|
||||
store.dispatch(
|
||||
addMessage({
|
||||
|
||||
12
src/core/utils/notifications.ts
Normal file
12
src/core/utils/notifications.ts
Normal file
@@ -0,0 +1,12 @@
|
||||
export const requestNotificationPermission = async (): Promise<void> => {
|
||||
if (window.Notification && Notification.permission !== 'denied') {
|
||||
await Notification.requestPermission();
|
||||
}
|
||||
};
|
||||
|
||||
export const showNotification = (title: string, body: string): void => {
|
||||
new Notification(title, {
|
||||
body,
|
||||
icon: 'android-512.png',
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user