Browse Source

Update descriptions, protobufs & bugfixes

pull/39/head
Sacha Weatherstone 4 years ago
parent
commit
a884fe28b3
  1. 12
      package.json
  2. 766
      pnpm-lock.yaml
  3. 15
      src/components/Dropdown.tsx
  4. 6
      src/components/PageComponents/Config/Device.tsx
  5. 12
      src/components/PageComponents/Config/Display.tsx
  6. 11
      src/components/PageComponents/Config/LoRa.tsx
  7. 10
      src/components/PageComponents/Config/Network.tsx
  8. 14
      src/components/PageComponents/Config/Position.tsx
  9. 22
      src/components/PageComponents/Config/Power.tsx
  10. 8
      src/components/PageComponents/Config/User.tsx
  11. 4
      src/components/PageComponents/Connect/BLE.tsx
  12. 4
      src/components/PageComponents/Connect/Serial.tsx
  13. 4
      src/components/Widgets/BatteryWidget.tsx
  14. 2
      src/components/Widgets/DeviceWidget.tsx
  15. 11
      src/components/Widgets/PeersWidget.tsx
  16. 4
      src/components/form/Checkbox.tsx
  17. 14
      src/components/form/Input.tsx
  18. 9
      src/components/form/Select.tsx
  19. 11
      src/pages/Messages.tsx
  20. 7
      src/validation/channelSettings.ts
  21. 3
      src/validation/config/lora.ts

12
package.json

@ -8,7 +8,8 @@
"build": "tsc && vite build", "build": "tsc && vite build",
"preview": "vite preview", "preview": "vite preview",
"package": "gzipper c -i html,js,css,png,ico,svg,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ $(ls ./dist/output/)", "package": "gzipper c -i html,js,css,png,ico,svg,webmanifest,txt dist dist/output && tar -cvf dist/build.tar -C ./dist/output/ $(ls ./dist/output/)",
"format": "prettier --write 'src/**/*.{ts,tsx}' && eslint src/*.{ts,tsx}" "format": "prettier --write 'src/**/*.{ts,tsx}' && eslint src/*.{ts,tsx}",
"check:unimported": "unimported"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -20,11 +21,11 @@
"homepage": "https://meshtastic.org", "homepage": "https://meshtastic.org",
"dependencies": { "dependencies": {
"@emeraldpay/hashicon-react": "^0.5.2", "@emeraldpay/hashicon-react": "^0.5.2",
"@headlessui/react": "^1.7.2", "@headlessui/react": "^1.7.3",
"@heroicons/react": "^2.0.11", "@heroicons/react": "^2.0.11",
"@hookform/resolvers": "^2.9.8", "@hookform/resolvers": "^2.9.8",
"@meshtastic/eslint-config": "^1.0.8", "@meshtastic/eslint-config": "^1.0.8",
"@meshtastic/meshtasticjs": "^0.6.103", "@meshtastic/meshtasticjs": "^0.6.104",
"@tailwindcss/line-clamp": "^0.4.2", "@tailwindcss/line-clamp": "^0.4.2",
"@tailwindcss/typography": "^0.5.7", "@tailwindcss/typography": "^0.5.7",
"base64-js": "^1.5.1", "base64-js": "^1.5.1",
@ -47,7 +48,7 @@
"devDependencies": { "devDependencies": {
"@types/chrome": "^0.0.197", "@types/chrome": "^0.0.197",
"@types/geodesy": "^2.2.3", "@types/geodesy": "^2.2.3",
"@types/node": "^18.7.23", "@types/node": "^18.8.0",
"@types/react": "^18.0.21", "@types/react": "^18.0.21",
"@types/react-dom": "^18.0.6", "@types/react-dom": "^18.0.6",
"@types/w3c-web-serial": "^1.0.2", "@types/w3c-web-serial": "^1.0.2",
@ -55,7 +56,7 @@
"@vitejs/plugin-react": "^2.1.0", "@vitejs/plugin-react": "^2.1.0",
"autoprefixer": "^10.4.12", "autoprefixer": "^10.4.12",
"gzipper": "^7.1.0", "gzipper": "^7.1.0",
"postcss": "^8.4.16", "postcss": "^8.4.17",
"prettier": "^2.7.1", "prettier": "^2.7.1",
"prettier-plugin-tailwindcss": "^0.1.13", "prettier-plugin-tailwindcss": "^0.1.13",
"rollup-plugin-visualizer": "^5.8.2", "rollup-plugin-visualizer": "^5.8.2",
@ -63,6 +64,7 @@
"tar": "^6.1.11", "tar": "^6.1.11",
"tslib": "^2.4.0", "tslib": "^2.4.0",
"typescript": "^4.8.4", "typescript": "^4.8.4",
"unimported": "^1.22.0",
"vite": "^3.1.4", "vite": "^3.1.4",
"vite-plugin-environment": "^1.1.2" "vite-plugin-environment": "^1.1.2"
} }

766
pnpm-lock.yaml

File diff suppressed because it is too large

15
src/components/Dropdown.tsx

@ -3,25 +3,36 @@ import type React from "react";
import { Disclosure } from "@headlessui/react"; import { Disclosure } from "@headlessui/react";
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline"; import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";
import { Mono } from "./Mono.js";
export interface DropdownProps { export interface DropdownProps {
title: string; title: string;
stat?: number;
icon: JSX.Element; icon: JSX.Element;
defaultOpen?: boolean;
children: React.ReactNode; children: React.ReactNode;
} }
export const Dropdown = ({ export const Dropdown = ({
title, title,
stat,
icon, icon,
defaultOpen,
children, children,
}: DropdownProps): JSX.Element => { }: DropdownProps): JSX.Element => {
return ( return (
<Disclosure defaultOpen> <Disclosure defaultOpen={defaultOpen}>
{({ open }) => ( {({ open }) => (
<> <>
<Disclosure.Button className="flex h-8 justify-between bg-slate-100 px-2 hover:bg-slate-200"> <Disclosure.Button className="group flex h-8 justify-between bg-slate-100 px-2 hover:bg-slate-200">
<div className="my-auto flex gap-2 text-slate-700"> <div className="my-auto flex gap-2 text-slate-700">
<div className="my-auto">{icon}</div> <div className="my-auto">{icon}</div>
<span className="text-lg font-medium">{title}</span> <span className="text-lg font-medium">{title}</span>
{stat !== undefined && (
<span className="my-auto flex rounded-full bg-slate-200 px-3 py-0.5 group-hover:bg-slate-300">
<Mono>{stat}</Mono>
</span>
)}
</div> </div>
<div className="my-auto text-slate-600"> <div className="my-auto text-slate-600">
{open ? ( {open ? (

6
src/components/PageComponents/Config/Device.tsx

@ -58,7 +58,7 @@ export const Device = (): JSX.Element => {
> >
<Select <Select
label="Role" label="Role"
description="This is a description." description="What role the device performs on the mesh"
{...register("role", { valueAsNumber: true })} {...register("role", { valueAsNumber: true })}
> >
{renderOptions(Protobuf.Config_DeviceConfig_Role)} {renderOptions(Protobuf.Config_DeviceConfig_Role)}
@ -69,7 +69,7 @@ export const Device = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Serial Output Enabled" label="Serial Output Enabled"
description="Description" description="Disable the device's serial console"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -81,7 +81,7 @@ export const Device = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Enabled Debug Log" label="Enabled Debug Log"
description="Description" description="Output debugging information to the device's serial port (auto disables when serial client is connected)"
checked={value} checked={value}
{...rest} {...rest}
/> />

12
src/components/PageComponents/Config/Display.tsx

@ -58,21 +58,21 @@ export const Display = (): JSX.Element => {
> >
<Input <Input
label="Screen Timeout" label="Screen Timeout"
description="This is a description." description="Turn off the display after this long"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
{...register("screenOnSecs", { valueAsNumber: true })} {...register("screenOnSecs", { valueAsNumber: true })}
/> />
<Input <Input
label="Carousel Delay" label="Carousel Delay"
description="This is a description." description="How fast to cycle through windows"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
{...register("autoScreenCarouselSecs", { valueAsNumber: true })} {...register("autoScreenCarouselSecs", { valueAsNumber: true })}
/> />
<Select <Select
label="GPS Display Units" label="GPS Display Units"
description="This is a description." description="Coordinate display format"
{...register("gpsFormat", { valueAsNumber: true })} {...register("gpsFormat", { valueAsNumber: true })}
> >
{renderOptions(Protobuf.Config_DisplayConfig_GpsCoordinateFormat)} {renderOptions(Protobuf.Config_DisplayConfig_GpsCoordinateFormat)}
@ -83,7 +83,7 @@ export const Display = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Compass North Top" label="Compass North Top"
description="Description" description="Fix north to the top of compass"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -95,7 +95,7 @@ export const Display = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Flip Screen" label="Flip Screen"
description="Description" description="Flip display 180 degrees"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -103,7 +103,7 @@ export const Display = (): JSX.Element => {
/> />
<Select <Select
label="Display Units" label="Display Units"
description="This is a description." description="Display metric or imperial units"
{...register("units", { valueAsNumber: true })} {...register("units", { valueAsNumber: true })}
> >
{renderOptions(Protobuf.Config_DisplayConfig_DisplayUnits)} {renderOptions(Protobuf.Config_DisplayConfig_DisplayUnits)}

11
src/components/PageComponents/Config/LoRa.tsx

@ -70,7 +70,7 @@ export const LoRa = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Use Preset" label="Use Preset"
description="Description" description="Use one of the predefined modem presets"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -78,7 +78,7 @@ export const LoRa = (): JSX.Element => {
/> />
<Select <Select
label="Preset" label="Preset"
description="This is a description." description="Modem preset to use"
disabled={!usePreset} disabled={!usePreset}
{...register("modemPreset", { valueAsNumber: true })} {...register("modemPreset", { valueAsNumber: true })}
> >
@ -159,6 +159,13 @@ export const LoRa = (): JSX.Element => {
error={errors.txPower?.message} error={errors.txPower?.message}
{...register("txPower", { valueAsNumber: true })} {...register("txPower", { valueAsNumber: true })}
/> />
<Input
label="Channel Number"
description="LoRa channel number"
type="number"
error={errors.channelNum?.message}
{...register("channelNum", { valueAsNumber: true })}
/>
</Form> </Form>
); );
}; };

10
src/components/PageComponents/Config/Network.tsx

@ -69,7 +69,7 @@ export const Network = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="WiFi Enabled" label="WiFi Enabled"
description="Description" description="Enable or disbale the WiFi radio"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -77,7 +77,7 @@ export const Network = (): JSX.Element => {
/> />
<Select <Select
label="WiFi Mode" label="WiFi Mode"
description="This is a description." description="How the WiFi radio should be used"
disabled={!wifiEnabled} disabled={!wifiEnabled}
{...register("wifiMode", { valueAsNumber: true })} {...register("wifiMode", { valueAsNumber: true })}
> >
@ -85,7 +85,7 @@ export const Network = (): JSX.Element => {
</Select> </Select>
<Input <Input
label="SSID" label="SSID"
description="This is a description." description="Network name"
error={errors.wifiSsid?.message} error={errors.wifiSsid?.message}
disabled={!wifiEnabled} disabled={!wifiEnabled}
{...register("wifiSsid")} {...register("wifiSsid")}
@ -93,14 +93,14 @@ export const Network = (): JSX.Element => {
<Input <Input
label="PSK" label="PSK"
type="password" type="password"
description="This is a description." description="Network password"
error={errors.wifiPsk?.message} error={errors.wifiPsk?.message}
disabled={!wifiEnabled} disabled={!wifiEnabled}
{...register("wifiPsk")} {...register("wifiPsk")}
/> />
<Input <Input
label="NTP Server" label="NTP Server"
description="This is a description." description="NTP server for time synchronization"
error={errors.ntpServer?.message} error={errors.ntpServer?.message}
{...register("ntpServer")} {...register("ntpServer")}
/> />

14
src/components/PageComponents/Config/Position.tsx

@ -57,7 +57,7 @@ export const Position = (): JSX.Element => {
<Input <Input
suffix="Seconds" suffix="Seconds"
label="Broadcast Interval" label="Broadcast Interval"
description="This is a description." description="How often your position is sent out over the mesh"
type="number" type="number"
error={errors.positionBroadcastSecs?.message} error={errors.positionBroadcastSecs?.message}
{...register("positionBroadcastSecs", { valueAsNumber: true })} {...register("positionBroadcastSecs", { valueAsNumber: true })}
@ -68,7 +68,7 @@ export const Position = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Enable Smart Position" label="Enable Smart Position"
description="Description" description="Only send position when there has been a meaningfull change in location"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -80,7 +80,7 @@ export const Position = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Use Fixed Position" label="Use Fixed Position"
description="Description" description="Don't report GPS position, but a manually specified one"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -92,7 +92,7 @@ export const Position = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="GPS Enabled" label="GPS Enabled"
description="Description" description="Enable the internal GPS module"
checked={value} checked={value}
{...rest} {...rest}
/> />
@ -101,14 +101,14 @@ export const Position = (): JSX.Element => {
<Input <Input
suffix="Seconds" suffix="Seconds"
label="GPS Update Interval" label="GPS Update Interval"
description="This is a description." description="How often a GPS fix should be acquired"
type="number" type="number"
error={errors.gpsUpdateInterval?.message} error={errors.gpsUpdateInterval?.message}
{...register("gpsUpdateInterval", { valueAsNumber: true })} {...register("gpsUpdateInterval", { valueAsNumber: true })}
/> />
<Input <Input
label="Last GPS Attempt" label="Fix Attempt Duration"
description="This is a description." description="How long the device will try to get a fix for"
type="number" type="number"
error={errors.gpsAttemptTime?.message} error={errors.gpsAttemptTime?.message}
{...register("gpsAttemptTime", { valueAsNumber: true })} {...register("gpsAttemptTime", { valueAsNumber: true })}

22
src/components/PageComponents/Config/Power.tsx

@ -55,7 +55,7 @@ export const Power = (): JSX.Element => {
> >
<Input <Input
label="Shutdown on battery delay" label="Shutdown on battery delay"
description="This is a description." description="Automatically shutdown node after this long when on battery, 0 for indefinite"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
error={errors.onBatteryShutdownAfterSecs?.message} error={errors.onBatteryShutdownAfterSecs?.message}
@ -66,7 +66,7 @@ export const Power = (): JSX.Element => {
control={control} control={control}
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Power Saving" label="Enable power saving mode"
description="Description" description="Description"
checked={value} checked={value}
{...rest} {...rest}
@ -75,14 +75,14 @@ export const Power = (): JSX.Element => {
/> />
<Input <Input
label="ADC Multiplier Override ratio" label="ADC Multiplier Override ratio"
description="This is a description." description="Used for tweaking battery voltage reading"
type="number" type="number"
error={errors.adcMultiplierOverride?.message} error={errors.adcMultiplierOverride?.message}
{...register("adcMultiplierOverride", { valueAsNumber: true })} {...register("adcMultiplierOverride", { valueAsNumber: true })}
/> />
<Input <Input
label="Minimum Wake Time" label="Minimum Wake Time"
description="This is a description." description="Minimum amount of time the device will stay away for after recieving a packet"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
error={errors.minWakeSecs?.message} error={errors.minWakeSecs?.message}
@ -90,31 +90,31 @@ export const Power = (): JSX.Element => {
/> />
<Input <Input
label="Mesh SDS Timeout" label="Mesh SDS Timeout"
description="This is a description." description="The device will enter super deep sleep after this time"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
error={errors.meshSdsTimeoutSecs?.message} error={errors.meshSdsTimeoutSecs?.message}
{...register("meshSdsTimeoutSecs", { valueAsNumber: true })} {...register("meshSdsTimeoutSecs", { valueAsNumber: true })}
/> />
<Input <Input
label="SDS" label="Super Deep Sleep Duration"
description="This is a description." description="How long the device will be in super deep sleep for"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
error={errors.sdsSecs?.message} error={errors.sdsSecs?.message}
{...register("sdsSecs", { valueAsNumber: true })} {...register("sdsSecs", { valueAsNumber: true })}
/> />
<Input <Input
label="LS" label="Light Sleep Duration"
description="This is a description." description="How long the device will be in light sleep for"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
error={errors.lsSecs?.message} error={errors.lsSecs?.message}
{...register("lsSecs", { valueAsNumber: true })} {...register("lsSecs", { valueAsNumber: true })}
/> />
<Input <Input
label="Wait Bluetooth" label="No Connection Bluetooth Disabled"
description="This is a description." description="If the device does not revieve a bluetooth connection, the BLE radio will be disabled after this long"
suffix="Seconds" suffix="Seconds"
type="number" type="number"
error={errors.waitBluetoothSecs?.message} error={errors.waitBluetoothSecs?.message}

8
src/components/PageComponents/Config/User.tsx

@ -80,13 +80,13 @@ export const User = (): JSX.Element => {
/> />
<Input <Input
label="Short Name" label="Short Name"
description="This is a description." description="Shown on small screens."
maxLength={3} maxLength={3}
{...register("shortName")} {...register("shortName")}
/> />
<Input <Input
label="Mac Address" label="Mac Address"
description="This is a description." description="Hardware address for this node."
disabled disabled
value={ value={
base16 base16
@ -97,7 +97,7 @@ export const User = (): JSX.Element => {
/> />
<Select <Select
label="Hardware" label="Hardware"
description="This is a description." description="Hardware model of this device."
disabled disabled
value={myNode?.data.user?.hwModel} value={myNode?.data.user?.hwModel}
> >
@ -109,7 +109,7 @@ export const User = (): JSX.Element => {
render={({ field: { value, ...rest } }) => ( render={({ field: { value, ...rest } }) => (
<Toggle <Toggle
label="Licenced Operator?" label="Licenced Operator?"
description="Description" description="Remove bandwidth restrictions in certain regions (HAM license required)"
checked={value} checked={value}
{...rest} {...rest}
/> />

4
src/components/PageComponents/Connect/BLE.tsx

@ -1,6 +1,7 @@
import type React from "react"; import type React from "react";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Mono } from "@app/components/Mono.js";
import { Button } from "@components/Button.js"; import { Button } from "@components/Button.js";
import { useAppStore } from "@core/stores/appStore.js"; import { useAppStore } from "@core/stores/appStore.js";
import { useDeviceStore } from "@core/stores/deviceStore.js"; import { useDeviceStore } from "@core/stores/deviceStore.js";
@ -48,6 +49,9 @@ export const BLE = (): JSX.Element => {
{device.name} {device.name}
</Button> </Button>
))} ))}
{bleDevices.length === 0 && (
<Mono className="m-auto">No devices paired yet.</Mono>
)}
</div> </div>
<Button <Button
iconBefore={<PlusCircleIcon className="w-4" />} iconBefore={<PlusCircleIcon className="w-4" />}

4
src/components/PageComponents/Connect/Serial.tsx

@ -1,6 +1,7 @@
import type React from "react"; import type React from "react";
import { useCallback, useEffect, useState } from "react"; import { useCallback, useEffect, useState } from "react";
import { Mono } from "@app/components/Mono.js";
import { Button } from "@components/Button.js"; import { Button } from "@components/Button.js";
import { useAppStore } from "@core/stores/appStore.js"; import { useAppStore } from "@core/stores/appStore.js";
import { useDeviceStore } from "@core/stores/deviceStore.js"; import { useDeviceStore } from "@core/stores/deviceStore.js";
@ -59,6 +60,9 @@ export const Serial = (): JSX.Element => {
{port.getInfo().usbVendorId} - {port.getInfo().usbProductId} {port.getInfo().usbVendorId} - {port.getInfo().usbProductId}
</Button> </Button>
))} ))}
{serialPorts.length === 0 && (
<Mono className="m-auto">No devices paired yet.</Mono>
)}
</div> </div>
<Button <Button
iconBefore={<PlusCircleIcon className="w-4" />} iconBefore={<PlusCircleIcon className="w-4" />}

4
src/components/Widgets/BatteryWidget.tsx

@ -17,7 +17,7 @@ export const BatteryWidget = ({
}: BatteryWidgetProps): JSX.Element => { }: BatteryWidgetProps): JSX.Element => {
return ( return (
<Card className="flex-col"> <Card className="flex-col">
<Dropdown title="Position" icon={<BoltIcon className="h-4" />}> <Dropdown title="Battery" icon={<BoltIcon className="h-4" />}>
<div className="flex"> <div className="flex">
<div className="flex w-20 bg-slate-700 p-3"> <div className="flex w-20 bg-slate-700 p-3">
<Battery100Icon className="m-auto h-12 text-white" /> <Battery100Icon className="m-auto h-12 text-white" />
@ -27,7 +27,7 @@ export const BatteryWidget = ({
<Mono>%</Mono> <Mono>%</Mono>
</span> </span>
<span className="m-auto text-lg"> <span className="m-auto text-lg">
{voltage} {voltage.toPrecision(2)}
<Mono>v</Mono> <Mono>v</Mono>
</span> </span>
</div> </div>

2
src/components/Widgets/DeviceWidget.tsx

@ -22,7 +22,7 @@ export const DeviceWidget = ({
reconnect, reconnect,
}: DeviceWidgetProps): JSX.Element => { }: DeviceWidgetProps): JSX.Element => {
return ( return (
<Card className="relative flex-col"> <Card className="relative shrink-0 flex-col">
<div className="absolute bottom-20 h-full w-full"> <div className="absolute bottom-20 h-full w-full">
<Hashicon size={350} value={nodeNum} /> <Hashicon size={350} value={nodeNum} />
</div> </div>

11
src/components/Widgets/PeersWidget.tsx

@ -21,8 +21,12 @@ export interface PeersWidgetProps {
export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => { export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => {
return ( return (
<Card className="flex-col"> <Card className="flex-col">
<Dropdown title="Peers" icon={<UserGroupIcon className="h-4" />}> <Dropdown
<div className="p-3"> title="Peers"
stat={peers.length}
icon={<UserGroupIcon className="h-4" />}
>
<div className="flex flex-col p-3">
{peers.map((peer) => ( {peers.map((peer) => (
<div <div
className="flex gap-2 rounded-md p-2 hover:bg-slate-100" className="flex gap-2 rounded-md p-2 hover:bg-slate-100"
@ -49,6 +53,9 @@ export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => {
</div> </div>
</div> </div>
))} ))}
{peers.length === 0 && (
<Mono className="m-auto">No devices discovered yet.</Mono>
)}
</div> </div>
</Dropdown> </Dropdown>
</Card> </Card>

4
src/components/form/Checkbox.tsx

@ -43,9 +43,7 @@ export const Checkbox = forwardRef<HTMLInputElement, CheckboxProps>(
<label htmlFor="comments" className="font-medium text-gray-700"> <label htmlFor="comments" className="font-medium text-gray-700">
{label} {label}
</label> </label>
<p id="comments-description" className="text-gray-500"> <p className="text-gray-500">{description}</p>
{description}
</p>
</div> </div>
</div> </div>
); );

14
src/components/form/Input.tsx

@ -39,9 +39,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
/> />
{suffix && ( {suffix && (
<div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3 font-mono"> <div className="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3 font-mono">
<span className="text-gray-500 sm:text-sm" id="price-currency"> <span className="text-gray-500 sm:text-sm">{suffix}</span>
{suffix}
</span>
</div> </div>
)} )}
{action && ( {action && (
@ -60,15 +58,9 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
)} )}
</div> </div>
{description && ( {description && (
<p className="mt-2 text-sm text-gray-500" id="email-description"> <p className="mt-2 text-sm text-gray-500">{description}</p>
{description}
</p>
)}
{error && (
<p className="mt-2 text-sm text-red-600" id="email-error">
{error}
</p>
)} )}
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
</div> </div>
); );
}); });

9
src/components/form/Select.tsx

@ -23,6 +23,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Input(
suffix, suffix,
action, action,
error, error,
disabled,
children, children,
...rest ...rest
}: SelectProps, }: SelectProps,
@ -41,7 +42,10 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Input(
ref={ref} ref={ref}
className={`flex h-10 w-full rounded-md bg-orange-100 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-orange-500 ${ className={`flex h-10 w-full rounded-md bg-orange-100 px-3 text-sm focus:outline-none focus:ring-2 focus:ring-orange-500 ${
prefix ? "rounded-l-none" : "" prefix ? "rounded-l-none" : ""
} ${action ? "rounded-r-none" : ""}`} } ${action ? "rounded-r-none" : ""} ${
disabled ? "cursor-not-allowed" : ""
}`}
disabled={disabled}
{...rest} {...rest}
> >
{options && {options &&
@ -60,6 +64,9 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Input(
</button> </button>
)} )}
</div> </div>
{description && (
<p className="mt-2 text-sm text-gray-500">{description}</p>
)}
</div> </div>
); );
}); });

11
src/pages/Messages.tsx

@ -7,11 +7,7 @@ import {
} from "@components/layout/page/TabbedContent.js"; } from "@components/layout/page/TabbedContent.js";
import { ChannelChat } from "@components/PageComponents/Messages/ChannelChat.js"; import { ChannelChat } from "@components/PageComponents/Messages/ChannelChat.js";
import { useDevice } from "@core/providers/useDevice.js"; import { useDevice } from "@core/providers/useDevice.js";
import { import { PencilIcon } from "@heroicons/react/24/outline";
EllipsisHorizontalCircleIcon,
PencilIcon,
XCircleIcon,
} from "@heroicons/react/24/outline";
import { Protobuf } from "@meshtastic/meshtasticjs"; import { Protobuf } from "@meshtastic/meshtasticjs";
export const MessagesPage = (): JSX.Element => { export const MessagesPage = (): JSX.Element => {
@ -24,11 +20,6 @@ export const MessagesPage = (): JSX.Element => {
: channel.config.index === 0 : channel.config.index === 0
? "Primary" ? "Primary"
: `Ch ${channel.config.index}`, : `Ch ${channel.config.index}`,
icon: channel.messages.length ? (
<EllipsisHorizontalCircleIcon className="h-4" />
) : (
<XCircleIcon className="h-4" />
),
element: () => <ChannelChat channel={channel} />, element: () => <ChannelChat channel={channel} />,
disabled: channel.config.role === Protobuf.Channel_Role.DISABLED, disabled: channel.config.role === Protobuf.Channel_Role.DISABLED,
}; };

7
src/validation/channelSettings.ts

@ -2,10 +2,9 @@ import { IsBoolean, IsInt, Length } from "class-validator";
import type { Protobuf } from "@meshtastic/meshtasticjs"; import type { Protobuf } from "@meshtastic/meshtasticjs";
export class ChannelSettingsValidation implements Protobuf.ChannelSettings { export class ChannelSettingsValidation
@IsInt() implements Omit<Protobuf.ChannelSettings, "channelNum">
channelNum: number; {
psk: Uint8Array; psk: Uint8Array;
@Length(1, 30) @Length(1, 30)

3
src/validation/config/lora.ts

@ -40,6 +40,9 @@ export class LoRaValidation implements Protobuf.Config_LoRaConfig {
@Min(0) @Min(0)
txPower: number; txPower: number;
@IsInt()
channelNum: number;
@IsArray() @IsArray()
ignoreIncoming: number[]; ignoreIncoming: number[];
} }

Loading…
Cancel
Save