Update descriptions, protobufs & bugfixes

This commit is contained in:
Sacha Weatherstone
2022-10-03 20:35:03 +10:30
parent 26dbe0c032
commit a884fe28b3
21 changed files with 744 additions and 205 deletions

View File

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

766
pnpm-lock.yaml generated
View File

File diff suppressed because it is too large Load Diff

View File

@@ -3,25 +3,36 @@ import type React from "react";
import { Disclosure } from "@headlessui/react";
import { ChevronDownIcon, ChevronUpIcon } from "@heroicons/react/24/outline";
import { Mono } from "./Mono.js";
export interface DropdownProps {
title: string;
stat?: number;
icon: JSX.Element;
defaultOpen?: boolean;
children: React.ReactNode;
}
export const Dropdown = ({
title,
stat,
icon,
defaultOpen,
children,
}: DropdownProps): JSX.Element => {
return (
<Disclosure defaultOpen>
<Disclosure defaultOpen={defaultOpen}>
{({ 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">{icon}</div>
<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 className="my-auto text-slate-600">
{open ? (

View File

@@ -58,7 +58,7 @@ export const Device = (): JSX.Element => {
>
<Select
label="Role"
description="This is a description."
description="What role the device performs on the mesh"
{...register("role", { valueAsNumber: true })}
>
{renderOptions(Protobuf.Config_DeviceConfig_Role)}
@@ -69,7 +69,7 @@ export const Device = (): JSX.Element => {
render={({ field: { value, ...rest } }) => (
<Toggle
label="Serial Output Enabled"
description="Description"
description="Disable the device's serial console"
checked={value}
{...rest}
/>
@@ -81,7 +81,7 @@ export const Device = (): JSX.Element => {
render={({ field: { value, ...rest } }) => (
<Toggle
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}
{...rest}
/>

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -17,7 +17,7 @@ export const BatteryWidget = ({
}: BatteryWidgetProps): JSX.Element => {
return (
<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 w-20 bg-slate-700 p-3">
<Battery100Icon className="m-auto h-12 text-white" />
@@ -27,7 +27,7 @@ export const BatteryWidget = ({
<Mono>%</Mono>
</span>
<span className="m-auto text-lg">
{voltage}
{voltage.toPrecision(2)}
<Mono>v</Mono>
</span>
</div>

View File

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

View File

@@ -21,8 +21,12 @@ export interface PeersWidgetProps {
export const PeersWidget = ({ peers }: PeersWidgetProps): JSX.Element => {
return (
<Card className="flex-col">
<Dropdown title="Peers" icon={<UserGroupIcon className="h-4" />}>
<div className="p-3">
<Dropdown
title="Peers"
stat={peers.length}
icon={<UserGroupIcon className="h-4" />}
>
<div className="flex flex-col p-3">
{peers.map((peer) => (
<div
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>
))}
{peers.length === 0 && (
<Mono className="m-auto">No devices discovered yet.</Mono>
)}
</div>
</Dropdown>
</Card>

View File

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

View File

@@ -39,9 +39,7 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
/>
{suffix && (
<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">
{suffix}
</span>
<span className="text-gray-500 sm:text-sm">{suffix}</span>
</div>
)}
{action && (
@@ -60,15 +58,9 @@ export const Input = forwardRef<HTMLInputElement, InputProps>(function Input(
)}
</div>
{description && (
<p className="mt-2 text-sm text-gray-500" id="email-description">
{description}
</p>
)}
{error && (
<p className="mt-2 text-sm text-red-600" id="email-error">
{error}
</p>
<p className="mt-2 text-sm text-gray-500">{description}</p>
)}
{error && <p className="mt-2 text-sm text-red-600">{error}</p>}
</div>
);
});

View File

@@ -23,6 +23,7 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Input(
suffix,
action,
error,
disabled,
children,
...rest
}: SelectProps,
@@ -41,7 +42,10 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Input(
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 ${
prefix ? "rounded-l-none" : ""
} ${action ? "rounded-r-none" : ""}`}
} ${action ? "rounded-r-none" : ""} ${
disabled ? "cursor-not-allowed" : ""
}`}
disabled={disabled}
{...rest}
>
{options &&
@@ -60,6 +64,9 @@ export const Select = forwardRef<HTMLSelectElement, SelectProps>(function Input(
</button>
)}
</div>
{description && (
<p className="mt-2 text-sm text-gray-500">{description}</p>
)}
</div>
);
});

View File

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

View File

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

View File

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