Browse Source

WIP

pull/1/head
Sacha Weatherstone 5 years ago
parent
commit
e172382765
  1. 17
      package.json
  2. 16
      src/App.tsx
  3. 2
      src/Main.tsx
  4. 2
      src/components/Sidebar.tsx
  5. 2
      src/components/Sidebar/Channels/Index.tsx
  6. 91
      src/components/Sidebar/Device/Index.tsx
  7. 122
      src/components/Sidebar/Device/Settings.tsx
  8. 80
      yarn.lock

17
package.json

@ -1,4 +1,8 @@
{
"name": "meshtastic-web",
"version": "1.0",
"description": "Meshtastic web client",
"license": "GPL-3.0-only",
"scripts": {
"start": "NODE_ENV=development snowpack dev",
"build": "snowpack build",
@ -7,13 +11,16 @@
"lint": "prettier --check \"src/**/*.{js,jsx,ts,tsx}\""
},
"dependencies": {
"@headlessui/react": "^1.1.1",
"@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-flags-select": "^2.1.2",
"rxjs": "^7.0.0",
"react-hook-form": "^7.5.2",
"react-json-pretty": "^2.2.0",
"rxjs": "^7.0.1",
"yarn": "^1.22.10"
},
"devDependencies": {
@ -22,13 +29,13 @@
"@snowpack/plugin-react-refresh": "^2.5.0",
"@snowpack/plugin-typescript": "^1.2.0",
"@types/react": "^17.0.5",
"@types/react-dom": "^17.0.0",
"@types/react-dom": "^17.0.4",
"@types/snowpack-env": "^2.3.2",
"autoprefixer": "^10.2.5",
"gzipper": "^4.5.0",
"postcss": "^8.2.14",
"postcss": "^8.2.15",
"postcss-cli": "^8.3.1",
"prettier": "^2.0.5",
"prettier": "^2.3.0",
"snowpack": "^3.3.7",
"tailwindcss": "^2.1.2",
"typescript": "^4.2.4"

16
src/App.tsx

@ -56,12 +56,7 @@ const App = () => {
lastMeshInterraction,
setLastMeshInterraction,
] = React.useState<number>(0);
const [
preferences,
setPreferences,
] = React.useState<Protobuf.RadioConfig_UserPreferences>(
Protobuf.RadioConfig_UserPreferences.create(),
);
const [language, setLanguage] = React.useState<LanguageEnum>(
LanguageEnum.ENGLISH,
);
@ -136,14 +131,6 @@ const App = () => {
const adminPacketEvent = connection.onAdminPacketEvent.subscribe(
(adminMessage) => {
switch (adminMessage.data.variant.oneofKind) {
case 'getRadioResponse':
if (adminMessage.data.variant.getRadioResponse.preferences) {
setPreferences(
adminMessage.data.variant.getRadioResponse.preferences,
);
}
break;
case 'getChannelResponse':
if (adminMessage.data.variant.getChannelResponse) {
let message = adminMessage.data.variant.getChannelResponse;
@ -183,7 +170,6 @@ const App = () => {
connection={connection}
nodes={nodes}
channels={channels}
preferences={preferences}
language={language}
setLanguage={setLanguage}
translations={translations}

2
src/Main.tsx

@ -17,7 +17,6 @@ interface MainProps {
nodes: Types.NodeInfoPacket[];
channels: Protobuf.Channel[];
isReady: boolean;
preferences: Protobuf.RadioConfig_UserPreferences;
language: LanguageEnum;
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
translations: languageTemplate;
@ -95,7 +94,6 @@ const Main = (props: MainProps) => {
isReady={props.isReady}
nodes={props.nodes}
channels={props.channels}
preferences={props.preferences}
connection={props.connection}
language={props.language}
setLanguage={props.setLanguage}

2
src/components/Sidebar.tsx

@ -16,7 +16,6 @@ interface SidebarProps {
isReady: boolean;
nodes: Types.NodeInfoPacket[];
channels: Protobuf.Channel[];
preferences: Protobuf.RadioConfig_UserPreferences;
connection: IHTTPConnection;
language: LanguageEnum;
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
@ -42,7 +41,6 @@ const Sidebar = (props: SidebarProps) => {
/>
<Device
isReady={props.isReady}
preferences={props.preferences}
connection={props.connection}
translations={props.translations}
/>

2
src/components/Sidebar/Channels/Index.tsx

@ -37,7 +37,7 @@ const Channels = (props: ChannelsProps) => {
<>
{props.channels.map((channel, index) => {
if (channel.role !== Protobuf.Channel_Role.DISABLED)
return <Channel channel={channel} />;
return <Channel key={index} channel={channel} />;
})}
</>
</Disclosure.Panel>

91
src/components/Sidebar/Device/Index.tsx

@ -1,19 +1,18 @@
import React from 'react';
import React, { Suspense } from 'react';
import { Disclosure } from '@headlessui/react';
import {
AdjustmentsIcon,
ChevronDownIcon,
ChevronRightIcon,
SaveIcon,
} from '@heroicons/react/outline';
import { IHTTPConnection, Protobuf } from '@meshtastic/meshtasticjs';
import type { IHTTPConnection } from '@meshtastic/meshtasticjs';
import type { languageTemplate } from '../../../App';
import Settings from './Settings';
interface DeviceProps {
isReady: boolean;
preferences: Protobuf.RadioConfig_UserPreferences;
connection: IHTTPConnection;
translations: languageTemplate;
}
@ -36,83 +35,13 @@ const Device = (props: DeviceProps) => {
</Disclosure.Button>
<Disclosure.Panel>
<>
<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={
props.preferences?.region ?? Protobuf.RegionCode.Unset
}
onChange={(e) => {
props.preferences.region = parseInt(e.target.value);
}}
>
<option value={Protobuf.RegionCode.ANZ}>
{Protobuf.RegionCode[Protobuf.RegionCode.ANZ]}
</option>
<option value={Protobuf.RegionCode.CN}>
{Protobuf.RegionCode[Protobuf.RegionCode.CN]}
</option>
<option value={Protobuf.RegionCode.EU433}>
{Protobuf.RegionCode[Protobuf.RegionCode.EU433]}
</option>
<option value={Protobuf.RegionCode.EU865}>
{Protobuf.RegionCode[Protobuf.RegionCode.EU865]}
</option>
<option value={Protobuf.RegionCode.JP}>
{Protobuf.RegionCode[Protobuf.RegionCode.JP]}
</option>
<option value={Protobuf.RegionCode.KR}>
{Protobuf.RegionCode[Protobuf.RegionCode.KR]}
</option>
<option value={Protobuf.RegionCode.TW}>
{Protobuf.RegionCode[Protobuf.RegionCode.TW]}
</option>
<option value={Protobuf.RegionCode.US}>
{Protobuf.RegionCode[Protobuf.RegionCode.US]}
</option>
<option value={Protobuf.RegionCode.Unset}>
{Protobuf.RegionCode[Protobuf.RegionCode.Unset]}
</option>
</select>
</div>
</div>
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
<div className="my-auto">
{props.translations.device_wifi_ssid}
</div>
<div className="flex shadow-md rounded-md ml-2">
<input
onChange={() => {}}
type="text"
value={props.preferences.wifiSsid}
/>
</div>
</div>
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
<div className="my-auto">
{props.translations.device_wifi_psk}
</div>
<div className="flex shadow-md rounded-md ml-2">
<input
type="password"
value={props.preferences.wifiPassword}
/>
</div>
</div>
<div className="flex bg-gray-100 group p-1 cursor-pointer hover:bg-gray-200 border-b">
<div
className="flex m-auto font-medium group-hover:text-gray-700"
onClick={() => {
props.connection.setPreferences(props.preferences);
}}
>
<SaveIcon className="m-auto mr-2 group-hover:text-gray-700 w-5 h-5" />
{props.translations.save_changes_button}
</div>
</div>
<Suspense fallback={<div>loading</div>}>
<Settings
connection={props.connection}
isReady={props.isReady}
translations={props.translations}
/>
</Suspense>
</>
</Disclosure.Panel>
</>

122
src/components/Sidebar/Device/Settings.tsx

@ -0,0 +1,122 @@
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';
export interface SettingsProps {
isReady: boolean;
connection: IHTTPConnection;
translations: languageTemplate;
}
const Settings = (props: SettingsProps) => {
React.useEffect(() => {
const a = useObservableSuspense(
new ObservableResource(
props.connection.onAdminPacketEvent.asObservable(),
),
);
const adminPacketEvent = props.connection.onAdminPacketEvent.subscribe(
(adminMessage) => {
switch (adminMessage.data.variant.oneofKind) {
case 'getRadioResponse':
if (adminMessage.data.variant.getRadioResponse.preferences) {
setPreferences(
adminMessage.data.variant.getRadioResponse.preferences,
);
}
}
},
);
return () => adminPacketEvent.unsubscribe();
}, []);
const [
preferences,
setPreferences,
] = React.useState<Protobuf.RadioConfig_UserPreferences>();
const {
register,
setValue,
handleSubmit,
formState: { errors },
} = 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);
// }}
>
<option value={Protobuf.RegionCode.ANZ}>
{Protobuf.RegionCode[Protobuf.RegionCode.ANZ]}
</option>
<option value={Protobuf.RegionCode.CN}>
{Protobuf.RegionCode[Protobuf.RegionCode.CN]}
</option>
<option value={Protobuf.RegionCode.EU433}>
{Protobuf.RegionCode[Protobuf.RegionCode.EU433]}
</option>
<option value={Protobuf.RegionCode.EU865}>
{Protobuf.RegionCode[Protobuf.RegionCode.EU865]}
</option>
<option value={Protobuf.RegionCode.JP}>
{Protobuf.RegionCode[Protobuf.RegionCode.JP]}
</option>
<option value={Protobuf.RegionCode.KR}>
{Protobuf.RegionCode[Protobuf.RegionCode.KR]}
</option>
<option value={Protobuf.RegionCode.TW}>
{Protobuf.RegionCode[Protobuf.RegionCode.TW]}
</option>
<option value={Protobuf.RegionCode.US}>
{Protobuf.RegionCode[Protobuf.RegionCode.US]}
</option>
<option value={Protobuf.RegionCode.Unset}>
{Protobuf.RegionCode[Protobuf.RegionCode.Unset]}
</option>
</select>
</div>
</div>
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
<div className="my-auto">{props.translations.device_wifi_ssid}</div>
<div className="flex shadow-md rounded-md ml-2">
<input {...register('wifiSsid', {})} type="text" />
</div>
</div>
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
<div className="my-auto">{props.translations.device_wifi_psk}</div>
<div className="flex shadow-md rounded-md ml-2">
<input {...register('wifiPassword', {})} type="password" />
</div>
</div>
<div className="flex bg-gray-100 group p-1 cursor-pointer hover:bg-gray-200 border-b">
<button
type="submit"
className="flex m-auto font-medium group-hover:text-gray-700"
>
<SaveIcon className="m-auto mr-2 group-hover:text-gray-700 w-5 h-5" />
{props.translations.save_changes_button}
</button>
</div>
<JSONPretty data={preferences} />
</form>
);
};
export default Settings;

80
yarn.lock

@ -213,10 +213,10 @@
dependencies:
purgecss "^3.1.3"
"@headlessui/react@^1.1.1":
version "1.1.1"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.1.1.tgz#71ecb3444eb21947ceefe768a25efaba4f8eceb0"
integrity sha512-fxNKxRrjNXdNYNMhAVrv1nz0gIMX3JhFizTA9lNrEC8+aY3JR00GZTPhuG785RZGvnHXCdYCGHeAhqw9uRNRrA==
"@headlessui/react@^1.2.0":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@headlessui/react/-/react-1.2.0.tgz#e48652bfce82ddf73d7f331faeb9db6526ee6874"
integrity sha512-19DkLz8gDgbi+WvkoTzi9vs0NK9TJf94vbYhMzB4LYJo03Kili0gmvXT9CiKZoxXZ7YAvy/b1U1oQKEnjWrqxw==
"@heroicons/react@^1.0.1":
version "1.0.1"
@ -358,10 +358,10 @@
resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.3.tgz#2ab0d5da2e5815f94b0b9d4b95d1e5f243ab2ca7"
integrity sha512-KfRL3PuHmqQLOG+2tGpRO26Ctg+Cq1E01D2DMriKEATHgWLfeNDmq9e29Q9WIky0dQ3NPkd1mzYH8Lm936Z9qw==
"@types/react-dom@^17.0.0":
version "17.0.3"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.3.tgz#7fdf37b8af9d6d40127137865bb3fff8871d7ee1"
integrity sha512-4NnJbCeWE+8YBzupn/YrJxZ8VnjcJq5iR1laqQ1vkpQgBiA7bwk0Rp24fxsdNinzJY2U+HHS4dJJDPdoMjdJ7w==
"@types/react-dom@^17.0.4":
version "17.0.4"
resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-17.0.4.tgz#d65159a847aca2a0fc87a7544a2f8fece8754d04"
integrity sha512-Wb6rlnPJfqbhpkvYN39y1NM/pOGGPzzIRquu0RdUMvTwgXNvASFO7pdtrtvyxGTQNb9wzBaQxXAWDdEqegZw2A==
dependencies:
"@types/react" "*"
@ -1826,7 +1826,7 @@ lodash@^4.17.19, lodash@^4.17.21:
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
loose-envify@^1.1.0:
loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@ -1995,6 +1995,11 @@ nanoid@^3.1.22:
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.22.tgz#b35f8fb7d151990a8aebd5aa5015c03cf726f844"
integrity sha512-/2ZUaJX2ANuLtTvqTlgqBQNJoQO398KyJgZloL0PZkC0dpysjncRUPsFe3DUPzz/y3h+u7C46np8RMuvF3jsSQ==
nanoid@^3.1.23:
version "3.1.23"
resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.23.tgz#f744086ce7c2bc47ee0a8472574d5c78e4183a81"
integrity sha512-FiB0kzdP0FFVGDKlRLEQ1BgDzU87dy5NnzjeW9YZNt+/c3+q82EQDUwniSAUxp/F0gFNI1ZhKU1FqYsMuqZVnw==
node-emoji@^1.8.1:
version "1.10.0"
resolved "https://registry.yarnpkg.com/node-emoji/-/node-emoji-1.10.0.tgz#8886abd25d9c7bb61802a658523d1f8d2a89b2da"
@ -2166,6 +2171,11 @@ object.assign@^4.1.2:
has-symbols "^1.0.1"
object-keys "^1.1.1"
observable-hooks@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/observable-hooks/-/observable-hooks-4.0.3.tgz#1113d04787fc971481b10cdbdf73c863f90b612f"
integrity sha512-cT0dqaj7xlKVzp3FyJYq+zE8os3eRgv2LoxKwv0JcU6X+ZLHD4ACfXC+IER+8uqLX4erVXzcmMkyVhCaxCy9gQ==
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
@ -2388,19 +2398,19 @@ postcss@^8.1.6, postcss@^8.2.1:
nanoid "^3.1.22"
source-map "^0.6.1"
postcss@^8.2.14:
version "8.2.14"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.14.tgz#dcf313eb8247b3ce8078d048c0e8262ca565ad2b"
integrity sha512-+jD0ZijcvyCqPQo/m/CW0UcARpdFylq04of+Q7RKX6f/Tu+dvpUI/9Sp81+i6/vJThnOBX09Quw0ZLOVwpzX3w==
postcss@^8.2.15:
version "8.2.15"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.2.15.tgz#9e66ccf07292817d226fc315cbbf9bc148fbca65"
integrity sha512-2zO3b26eJD/8rb106Qu2o7Qgg52ND5HPjcyQiK2B98O388h43A448LCslC0dI2P97wCAQRJsFvwTRcXxTKds+Q==
dependencies:
colorette "^1.2.2"
nanoid "^3.1.22"
nanoid "^3.1.23"
source-map "^0.6.1"
prettier@^2.0.5:
version "2.2.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5"
integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==
prettier@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18"
integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w==
pretty-hrtime@^1.0.3:
version "1.0.3"
@ -2425,6 +2435,15 @@ promise-retry@^2.0.1:
err-code "^2.0.2"
retry "^0.12.0"
prop-types@^15.6.2:
version "15.7.2"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
integrity sha512-8QQikdH7//R2vurIJSutZ1smHYTcLpRWEOlHnzcWHmBYrOGUysKwSsrC89BCiFj3CbrfJ/nXFdJepOVrY1GCHQ==
dependencies:
loose-envify "^1.4.0"
object-assign "^4.1.1"
react-is "^16.8.1"
psl@^1.1.28:
version "1.8.0"
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
@ -2476,6 +2495,23 @@ react-flags-select@^2.1.2:
dependencies:
classnames "^2.2.6"
react-hook-form@^7.5.2:
version "7.5.2"
resolved "https://registry.yarnpkg.com/react-hook-form/-/react-hook-form-7.5.2.tgz#4f8da6d22ae67aa18ce170a0980bd7e1e7bd6917"
integrity sha512-fRA6TieC+wsumcdAM7OTeWSa+s+qG2ZlWfTXB2gpOwVeWpJxDwUpZZRfZdU9Bj6TEn1v/ZPJg/1xbmUGVI+MWA==
react-is@^16.8.1:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
react-json-pretty@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/react-json-pretty/-/react-json-pretty-2.2.0.tgz#9ba907d2b08d87e90456d87b6025feeceb8f63cf"
integrity sha512-3UMzlAXkJ4R8S4vmkRKtvJHTewG4/rn1Q18n0zqdu/ipZbUPLVZD+QwC7uVcD/IAY3s8iNVHlgR2dMzIUS0n1A==
dependencies:
prop-types "^15.6.2"
react-refresh@^0.9.0:
version "0.9.0"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.9.0.tgz#71863337adc3e5c2f8a6bfddd12ae3bfe32aafbf"
@ -2627,10 +2663,10 @@ rxjs@^6.6.7:
dependencies:
tslib "^1.9.0"
rxjs@^7.0.0:
version "7.0.0"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.0.0.tgz#c55d67c52aee8804d32ab60965e335bd41e2dc2d"
integrity sha512-I1V/ArAtGJg4kmCfms8fULm0SwYgEsAf2d5WPCBGzTYm2qTjO3Tx4EDFaGjbOox8CeEsC69jQK22mnmfyA26sw==
rxjs@^7.0.1:
version "7.0.1"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.0.1.tgz#5f41c4f991cea550471fc5d215727390103702c7"
integrity sha512-wViQ4Vgps1xJwqWIBooMNN44usCSthL7wCUl4qWqrVjhGfWyVyXcxlYzfDKkJKACQvZMTOft/jJ3RkbwK1j9QQ==
dependencies:
tslib "~2.1.0"

Loading…
Cancel
Save