+
{suffix}
)}
diff --git a/src/core/stores/appStore.ts b/src/core/stores/appStore.ts
index fa46cb57..2098c17b 100644
--- a/src/core/stores/appStore.ts
+++ b/src/core/stores/appStore.ts
@@ -26,6 +26,7 @@ interface AppState {
rasterSources: RasterSource[];
commandPaletteOpen: boolean;
darkMode: boolean;
+ nodeNumToBeRemoved: number;
accent: AccentColor;
connectDialogOpen: boolean;
@@ -38,6 +39,7 @@ interface AppState {
removeDevice: (deviceId: number) => void;
setCommandPaletteOpen: (open: boolean) => void;
setDarkMode: (enabled: boolean) => void;
+ setNodeNumToBeRemoved: (nodeNum: number) => void;
setAccent: (color: AccentColor) => void;
setConnectDialogOpen: (open: boolean) => void;
}
@@ -51,6 +53,7 @@ export const useAppStore = create
()((set) => ({
darkMode: window.matchMedia("(prefers-color-scheme: dark)").matches,
accent: "orange",
connectDialogOpen: false,
+ nodeNumToBeRemoved: 0,
setRasterSources: (sources: RasterSource[]) => {
set(
@@ -99,6 +102,10 @@ export const useAppStore = create()((set) => ({
}),
);
},
+ setNodeNumToBeRemoved: (nodeNum) =>
+ set((state) => ({
+ nodeNumToBeRemoved: nodeNum
+ })),
setAccent(color) {
set(
produce((draft) => {
diff --git a/src/core/stores/deviceStore.ts b/src/core/stores/deviceStore.ts
index ecd1f7f0..37e0a638 100644
--- a/src/core/stores/deviceStore.ts
+++ b/src/core/stores/deviceStore.ts
@@ -24,7 +24,8 @@ export type DialogVariant =
| "QR"
| "shutdown"
| "reboot"
- | "deviceName";
+ | "deviceName"
+ | "nodeRemoval";
export interface Device {
id: number;
@@ -55,6 +56,7 @@ export interface Device {
shutdown: boolean;
reboot: boolean;
deviceName: boolean;
+ nodeRemoval: boolean;
};
setStatus: (status: Types.DeviceStatusEnum) => void;
@@ -76,6 +78,7 @@ export interface Device {
addMessage: (message: MessageWithState) => void;
addTraceRoute: (traceroute: Types.PacketMetadata) => void;
addMetadata: (from: number, metadata: Protobuf.Mesh.DeviceMetadata) => void;
+ removeNode: (nodeNum: number) => void;
setMessageState: (
type: "direct" | "broadcast",
channelIndex: Types.ChannelNumber,
@@ -133,6 +136,7 @@ export const useDeviceStore = create((set, get) => ({
shutdown: false,
reboot: false,
deviceName: false,
+ nodeRemoval: false,
},
pendingSettingsChanges: false,
messageDraft: "",
@@ -518,6 +522,17 @@ export const useDeviceStore = create((set, get) => ({
}),
);
},
+ removeNode: (nodeNum) => {
+ set(
+ produce((draft) => {
+ const device = draft.devices.get(id);
+ if (!device) {
+ return;
+ }
+ device.nodes.delete(nodeNum);
+ })
+ )
+ },
setMessageState: (
type: "direct" | "broadcast",
channelIndex: Types.ChannelNumber,
diff --git a/src/pages/Nodes.tsx b/src/pages/Nodes.tsx
index 1ece9be5..f9a46cb0 100644
--- a/src/pages/Nodes.tsx
+++ b/src/pages/Nodes.tsx
@@ -6,9 +6,19 @@ import { useDevice } from "@core/stores/deviceStore.js";
import { Hashicon } from "@emeraldpay/hashicon-react";
import { Protobuf } from "@meshtastic/js";
import { base16 } from "rfc4648";
+import { Button } from "@components/UI/Button.js";
+import { TrashIcon } from "lucide-react";
+import { useAppStore } from "@app/core/stores/appStore";
+
+
+export interface DeleteNoteDialogProps {
+ open: boolean;
+ onOpenChange: (open: boolean) => void;
+}
export const NodesPage = (): JSX.Element => {
- const { nodes, hardware } = useDevice();
+ const { nodes, hardware, setDialogOpen } = useDevice();
+ const { setNodeNumToBeRemoved } = useAppStore();
const filteredNodes = Array.from(nodes.values()).filter(
(n) => n.num !== hardware.myNodeNum,
@@ -27,6 +37,7 @@ export const NodesPage = (): JSX.Element => {
{ title: "Last Heard", type: "normal", sortable: true },
{ title: "SNR", type: "normal", sortable: true },
{ title: "Connection", type: "normal", sortable: true },
+ { title: "Remove", type: "normal", sortable: false },
]}
rows={filteredNodes.map((node) => [
,
@@ -57,12 +68,16 @@ export const NodesPage = (): JSX.Element => {
{(node.snr + 10) * 5}raw
,
- {node.lastHeard != 0 ?
- (node.viaMqtt === false && node.hopsAway === 0
- ? "Direct": node.hopsAway.toString() + " hops away")
- : "-"}
- {node.viaMqtt === true? ", via MQTT": ""}
-
+ {node.lastHeard != 0 ?
+ (node.viaMqtt === false && node.hopsAway === 0
+ ? "Direct": node.hopsAway.toString() + " hops away")
+ : "-"}
+ {node.viaMqtt === true? ", via MQTT": ""}
+ ,
+
])}
/>
diff --git a/src/validation/channel.ts b/src/validation/channel.ts
index 336e35e1..33349d06 100644
--- a/src/validation/channel.ts
+++ b/src/validation/channel.ts
@@ -41,4 +41,13 @@ export class Channel_SettingsValidation
@IsBoolean()
downlinkEnabled: boolean;
+
+ @IsBoolean()
+ positionEnabled: boolean;
+
+ @IsBoolean()
+ preciseLocation: boolean;
+
+ @IsInt()
+ positionPrecision: number;
}
diff --git a/src/validation/config/position.ts b/src/validation/config/position.ts
index 752a7093..2f035744 100644
--- a/src/validation/config/position.ts
+++ b/src/validation/config/position.ts
@@ -2,8 +2,10 @@ import type { Message } from "@bufbuild/protobuf";
import { Protobuf } from "@meshtastic/js";
import { IsArray, IsBoolean, IsEnum, IsInt } from "class-validator";
+const DeprecatedPositionValidationFields = ['gpsEnabled', 'gpsAttemptTime'];
+
export class PositionValidation
- implements Omit