From d8130f8a4ebe9bb0e771209d6dfcb6f3d1c544bc Mon Sep 17 00:00:00 2001 From: Jeremy Gallant Date: Sun, 4 May 2025 20:41:02 +0200 Subject: [PATCH] fix: easy linting errors & auto formatting Remove unused Add linting ignore on true parameter Autoformatting --- .../Config/Security/Security.tsx | 14 +- .../PageComponents/Connect/HTTP.tsx | 39 ++- src/components/ThemeSwitcher.tsx | 2 +- src/core/stores/messageStore/index.ts | 91 +++++-- src/core/subscriptions.ts | 17 +- src/pages/Messages.tsx | 246 ++++++++++++------ 6 files changed, 279 insertions(+), 130 deletions(-) diff --git a/src/components/PageComponents/Config/Security/Security.tsx b/src/components/PageComponents/Config/Security/Security.tsx index 6c6b880a..6b06ba2e 100644 --- a/src/components/PageComponents/Config/Security/Security.tsx +++ b/src/components/PageComponents/Config/Security/Security.tsx @@ -1,16 +1,12 @@ import { PkiRegenerateDialog } from "@components/Dialog/PkiRegenerateDialog.tsx"; import { DynamicForm } from "@components/Form/DynamicForm.tsx"; import { useAppStore } from "@core/stores/appStore.ts"; -import { - getX25519PrivateKey, - getX25519PublicKey, -} from "@core/utils/x25519.ts"; +import { getX25519PrivateKey, getX25519PublicKey } from "@core/utils/x25519.ts"; import type { SecurityValidation } from "@app/validation/config/security.ts"; import { create } from "@bufbuild/protobuf"; import { useDevice } from "@core/stores/deviceStore.ts"; import { Protobuf } from "@meshtastic/core"; import { fromByteArray, toByteArray } from "base64-js"; -import { Eye, EyeOff } from "lucide-react"; import { useReducer } from "react"; import { securityReducer } from "@components/PageComponents/Config/Security/securityReducer.tsx"; @@ -58,7 +54,8 @@ export const Security = () => { if (input.length % 4 !== 0) { addError( fieldName, - `${fieldName === "privateKey" ? "Private" : "Admin" + `${ + fieldName === "privateKey" ? "Private" : "Admin" } Key is required to be a 256 bit pre-shared key (PSK)`, ); return; @@ -73,7 +70,8 @@ export const Security = () => { console.error(e); addError( fieldName, - `Invalid ${fieldName === "privateKey" ? "Private" : "Admin" + `Invalid ${ + fieldName === "privateKey" ? "Private" : "Admin" } Key format`, ); } @@ -242,7 +240,7 @@ export const Security = () => { ? getErrorMessage("adminKey") : "", inputChange: adminKeyInputChangeEvent, - selectChange: () => { }, + selectChange: () => {}, bits: [{ text: "256 bit", value: "32", key: "bit256" }], devicePSKBitCount: state.privateKeyBitCount, hide: !state.adminKeyVisible, diff --git a/src/components/PageComponents/Connect/HTTP.tsx b/src/components/PageComponents/Connect/HTTP.tsx index c50c94b5..9d62462c 100644 --- a/src/components/PageComponents/Connect/HTTP.tsx +++ b/src/components/PageComponents/Connect/HTTP.tsx @@ -11,7 +11,7 @@ import { randId } from "@core/utils/randId.ts"; import { MeshDevice } from "@meshtastic/core"; import { TransportHTTP } from "@meshtastic/transport-http"; import { useState } from "react"; -import { useForm, useController } from "react-hook-form"; +import { useController, useForm } from "react-hook-form"; import { AlertTriangle } from "lucide-react"; import { useMessageStore } from "../../../core/stores/messageStore/index.ts"; @@ -20,7 +20,10 @@ interface FormData { tls: boolean; } -export const HTTP = ({ closeDialog, setConnectionInProgress, connectionInProgress }: TabElementProps) => { +export const HTTP = ( + { closeDialog, setConnectionInProgress, connectionInProgress }: + TabElementProps, +) => { const isURLHTTPS = location.protocol === "https:"; const { addDevice } = useDeviceStore(); @@ -30,8 +33,8 @@ export const HTTP = ({ closeDialog, setConnectionInProgress, connectionInProgres const { control, handleSubmit, register } = useForm({ defaultValues: { ip: ["client.meshtastic.org", "localhost"].includes( - globalThis.location.hostname, - ) + globalThis.location.hostname, + ) ? "meshtastic.local" : globalThis.location.host, tls: isURLHTTPS ? true : false, @@ -42,7 +45,9 @@ export const HTTP = ({ closeDialog, setConnectionInProgress, connectionInProgres field: { value: tlsValue, onChange: setTLS }, } = useController({ name: "tls", control }); - const [connectionError, setConnectionError] = useState<{ host: string; secure: boolean } | null>(null); + const [connectionError, setConnectionError] = useState< + { host: string; secure: boolean } | null + >(null); const onSubmit = handleSubmit(async (data) => { setConnectionInProgress(true); @@ -91,21 +96,31 @@ export const HTTP = ({ closeDialog, setConnectionInProgress, connectionInProgres {connectionError && (
- +

Connection Failed

- Could not connect to the device. {connectionError.secure && "If using HTTPS, you may need to accept a self-signed certificate first. "} + Could not connect to the device. {connectionError.secure && + "If using HTTPS, you may need to accept a self-signed certificate first. "} Please open{" "} - {`${connectionError.secure ? "https" : "http"}://${connectionError.host}`} + {`${ + connectionError.secure ? "https" : "http" + }://${connectionError.host}`} {" "} - in a new tab{connectionError.secure ? ", accept any TLS warnings if prompted, then try again" : ""}.{" "} + in a new tab{connectionError.secure + ? ", accept any TLS warnings if prompted, then try again" + : ""}.{" "} ); -}; \ No newline at end of file +}; diff --git a/src/components/ThemeSwitcher.tsx b/src/components/ThemeSwitcher.tsx index 979c974b..251ed2b3 100644 --- a/src/components/ThemeSwitcher.tsx +++ b/src/components/ThemeSwitcher.tsx @@ -9,7 +9,7 @@ export default function ThemeSwitcher({ }: { className?: string; }) { - const { theme, preference, setPreference } = useTheme(); + const { preference, setPreference } = useTheme(); const themeIcons = { light: , diff --git a/src/core/stores/messageStore/index.ts b/src/core/stores/messageStore/index.ts index 0dd4934e..724a5166 100644 --- a/src/core/stores/messageStore/index.ts +++ b/src/core/stores/messageStore/index.ts @@ -1,9 +1,19 @@ -import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; -import { produce } from 'immer'; -import { Types } from '@meshtastic/core'; -import { storageWithMapSupport } from "../storage/indexDB.ts"; -import { ChannelId, ClearMessageParams, ConversationId, GetMessagesParams, Message, MessageId, MessageLogMap, NodeNum, SetMessageStateParams } from "@core/stores/messageStore/types.ts"; +import { create } from "zustand"; +// import { persist } from 'zustand/middleware'; +import { produce } from "immer"; +import { Types } from "@meshtastic/core"; +// import { storageWithMapSupport } from "../storage/indexDB.ts"; +import { + ChannelId, + ClearMessageParams, + ConversationId, + GetMessagesParams, + Message, + MessageId, + MessageLogMap, + NodeNum, + SetMessageStateParams, +} from "@core/stores/messageStore/types.ts"; export enum MessageState { Ack = "ack", @@ -16,8 +26,11 @@ export enum MessageType { Broadcast = "broadcast", } -export function getConversationId(node1: NodeNum, node2: NodeNum): ConversationId { - return [node1, node2].sort((a, b) => a - b).join(':'); +export function getConversationId( + node1: NodeNum, + node2: NodeNum, +): ConversationId { + return [node1, node2].sort((a, b) => a - b).join(":"); } export interface MessageStore { @@ -25,9 +38,9 @@ export interface MessageStore { direct: Map; broadcast: Map; }; -}; +} export interface MessageStore { - messages: MessageStore['messages']; + messages: MessageStore["messages"]; draft: Map; nodeNum: number; // This device's node number activeChat: number; // Represents otherNodeNum for Direct, or channel for Broadcast @@ -47,7 +60,7 @@ export interface MessageStore { clearDraft: (key: Types.Destination) => void; } -const CURRENT_STORE_VERSION = 0; +// const CURRENT_STORE_VERSION = 0; export const useMessageStore = create()( // persist( @@ -82,17 +95,29 @@ export const useMessageStore = create()( if (message.type === MessageType.Direct) { const conversationId = getConversationId(message.from, message.to); if (!state.messages.direct.has(conversationId)) { - state.messages.direct.set(conversationId, new Map()); + state.messages.direct.set( + conversationId, + new Map(), + ); } - state.messages.direct.get(conversationId)!.set(message.messageId, message); + state.messages.direct.get(conversationId)!.set( + message.messageId, + message, + ); } else if (message.type === MessageType.Broadcast) { const channelId = message.channel as ChannelId; if (!state.messages.broadcast.has(channelId)) { - state.messages.broadcast.set(channelId, new Map()); + state.messages.broadcast.set( + channelId, + new Map(), + ); } - state.messages.broadcast.get(channelId)!.set(message.messageId, message); + state.messages.broadcast.get(channelId)!.set( + message.messageId, + message, + ); } - }) + }), ); }, @@ -103,7 +128,10 @@ export const useMessageStore = create()( let targetMessage: Message | undefined; if (params.type === MessageType.Direct) { - const conversationId = getConversationId(params.nodeA, params.nodeB); + const conversationId = getConversationId( + params.nodeA, + params.nodeB, + ); messageLog = state.messages.direct.get(conversationId); if (messageLog) { targetMessage = messageLog.get(params.messageId); @@ -118,9 +146,13 @@ export const useMessageStore = create()( if (targetMessage) { targetMessage.state = params.newState ?? MessageState.Ack; } else { - console.warn(`Message or conversation/channel not found for state update. Params: ${JSON.stringify(params)}`); + console.warn( + `Message or conversation/channel not found for state update. Params: ${ + JSON.stringify(params) + }`, + ); } - }) + }), ); }, getMessages: (params: GetMessagesParams): Message[] => { @@ -130,7 +162,6 @@ export const useMessageStore = create()( if (params.type === MessageType.Direct) { const conversationId = getConversationId(params.nodeA, params.nodeB); messageMap = state.messages.direct.get(conversationId); - } else { messageMap = state.messages.broadcast.get(params.channelId); } @@ -165,23 +196,29 @@ export const useMessageStore = create()( const deleted = messageLog.delete(params.messageId); if (deleted) { - console.log(`Deleted message ${params.messageId} from ${params.type} message ${parentKey}`); + console.log( + `Deleted message ${params.messageId} from ${params.type} message ${parentKey}`, + ); // Clean up empty MessageLogMap and its entry in the parent map if (messageLog.size === 0) { parentMap.delete(parentKey); console.log(`Cleaned up empty message entry for ${parentKey}`); } } else { - console.warn(`Message ${params.messageId} not found in ${params.type} chat ${parentKey} for deletion.`); + console.warn( + `Message ${params.messageId} not found in ${params.type} chat ${parentKey} for deletion.`, + ); } } else { - console.warn(`Message entry ${parentKey} not found for message deletion.`); + console.warn( + `Message entry ${parentKey} not found for message deletion.`, + ); } - }) + }), ); }, getDraft: (key) => { - return get().draft.get(key) ?? ''; + return get().draft.get(key) ?? ""; }, setDraft: (key, message) => { set(produce((state: MessageStore) => { @@ -198,7 +235,7 @@ export const useMessageStore = create()( state.messages.direct = new Map(); state.messages.broadcast = new Map(); })); - } + }, }), // { // name: 'meshtastic-message-store', @@ -209,4 +246,4 @@ export const useMessageStore = create()( // nodeNum: state.nodeNum, // }), // }) -) \ No newline at end of file +); diff --git a/src/core/subscriptions.ts b/src/core/subscriptions.ts index ab79aacd..e381a5fd 100644 --- a/src/core/subscriptions.ts +++ b/src/core/subscriptions.ts @@ -1,13 +1,13 @@ import type { Device } from "@core/stores/deviceStore.ts"; import { MeshDevice, Protobuf } from "@meshtastic/core"; -import { MessageState, MessageType, type MessageStore } from "./stores/messageStore/index.ts"; +import { type MessageStore, MessageType } from "./stores/messageStore/index.ts"; import PacketToMessageDTO from "@core/dto/PacketToMessageDTO.ts"; import NodeInfoFactory from "@core/dto/NodeNumToNodeInfoDTO.ts"; export const subscribeAll = ( device: Device, connection: MeshDevice, - messageStore: MessageStore + messageStore: MessageStore, ) => { let myNodeNum = 0; @@ -79,7 +79,6 @@ export const subscribeAll = ( device.setModuleConfig(moduleConfig); }); - connection.events.onMessagePacket.subscribe((messagePacket) => { // incoming and outgoing messages are handled by this event listener console.log("Message Packet", messagePacket); @@ -117,7 +116,6 @@ export const subscribeAll = ( }); }); - connection.events.onRoutingPacket.subscribe((routingPacket) => { if (routingPacket.data.variant.case === "errorReason") { switch (routingPacket.data.variant.value) { @@ -126,19 +124,24 @@ export const subscribeAll = ( break; case Protobuf.Mesh.Routing_Error.NO_CHANNEL: console.error(`Routing Error: ${routingPacket.data.variant.value}`); - device.setNodeError(routingPacket.from, Protobuf.Mesh.Routing_Error[routingPacket?.data?.variant?.value]); + device.setNodeError( + routingPacket.from, + Protobuf.Mesh.Routing_Error[routingPacket?.data?.variant?.value], + ); device.setDialogOpen("refreshKeys", true); break; case Protobuf.Mesh.Routing_Error.PKI_UNKNOWN_PUBKEY: console.error(`Routing Error: ${routingPacket.data.variant.value}`); - device.setNodeError(routingPacket.from, Protobuf.Mesh.Routing_Error[routingPacket?.data?.variant?.value]); + device.setNodeError( + routingPacket.from, + Protobuf.Mesh.Routing_Error[routingPacket?.data?.variant?.value], + ); device.setDialogOpen("refreshKeys", true); break; default: { break; } } - } }); }; diff --git a/src/pages/Messages.tsx b/src/pages/Messages.tsx index 074838c4..05e3bfa8 100644 --- a/src/pages/Messages.tsx +++ b/src/pages/Messages.tsx @@ -12,34 +12,55 @@ import { HashIcon, LockIcon, LockOpenIcon } from "lucide-react"; import { useCallback, useDeferredValue, useMemo, useState } from "react"; import { MessageInput } from "@components/PageComponents/Messages/MessageInput.tsx"; import { cn } from "@core/utils/cn.ts"; -import { MessageState, MessageType, useMessageStore } from "@core/stores/messageStore/index.ts"; +import { + MessageState, + MessageType, + useMessageStore, +} from "@core/stores/messageStore/index.ts"; import { useSidebar } from "@core/stores/sidebarStore.tsx"; import { Input } from "@components/UI/Input.tsx"; type NodeInfoWithUnread = Protobuf.Mesh.NodeInfo & { unreadCount: number }; export const MessagesPage = () => { - const { channels, getNodes, getNode, hasNodeError, unreadCounts, resetUnread, connection } = useDevice(); - const { getMyNodeNum, getMessages, setActiveChat, chatType, activeChat, setChatType, setMessageState, } = useMessageStore() + const { + channels, + getNodes, + getNode, + hasNodeError, + unreadCounts, + resetUnread, + connection, + } = useDevice(); + const { + getMyNodeNum, + getMessages, + setActiveChat, + chatType, + activeChat, + setChatType, + setMessageState, + } = useMessageStore(); const { toast } = useToast(); - const { isCollapsed } = useSidebar() + const { isCollapsed } = useSidebar(); const [searchTerm, setSearchTerm] = useState(""); const deferredSearch = useDeferredValue(searchTerm); const filteredNodes = (): NodeInfoWithUnread[] => { const lowerCaseSearchTerm = deferredSearch.toLowerCase(); - return getNodes(node => { - const longName = node.user?.longName?.toLowerCase() ?? ''; - const shortName = node.user?.shortName?.toLowerCase() ?? ''; - return longName.includes(lowerCaseSearchTerm) || shortName.includes(lowerCaseSearchTerm) + return getNodes((node) => { + const longName = node.user?.longName?.toLowerCase() ?? ""; + const shortName = node.user?.shortName?.toLowerCase() ?? ""; + return longName.includes(lowerCaseSearchTerm) || + shortName.includes(lowerCaseSearchTerm); }) .map((node) => ({ ...node, unreadCount: unreadCounts.get(node.num) ?? 0, })) .sort((a, b) => b.unreadCount - a.unreadCount); - } + }; const allChannels = Array.from(channels.values()); const filteredChannels = allChannels.filter( @@ -55,19 +76,39 @@ export const MessagesPage = () => { const isDirect = chatType === MessageType.Direct; const toValue = isDirect ? activeChat : MessageType.Broadcast; - const channelValue = isDirect ? Types.ChannelNumber.Primary : activeChat ?? 0; + const channelValue = isDirect + ? Types.ChannelNumber.Primary + : activeChat ?? 0; - console.log(`Sending message: "${message}" to: ${toValue}, channel: ${channelValue}, type: ${chatType}`); + console.log( + `Sending message: "${message}" to: ${toValue}, channel: ${channelValue}, type: ${chatType}`, + ); let messageId: number | undefined; try { - messageId = await connection?.sendText(message, toValue, true, channelValue); + messageId = await connection?.sendText( + message, + toValue, + true, + channelValue, + ); if (messageId !== undefined) { if (chatType === MessageType.Broadcast) { - setMessageState({ type: chatType, channelId: channelValue, messageId, newState: MessageState.Ack }); + setMessageState({ + type: chatType, + channelId: channelValue, + messageId, + newState: MessageState.Ack, + }); } else { - setMessageState({ type: chatType, nodeA: getMyNodeNum(), nodeB: activeChat, messageId, newState: MessageState.Ack }); + setMessageState({ + type: chatType, + nodeA: getMyNodeNum(), + nodeB: activeChat, + messageId, + newState: MessageState.Ack, + }); } } else { console.warn("sendText completed but messageId is undefined"); @@ -78,10 +119,21 @@ export const MessagesPage = () => { // Note: messageId might be undefined here if the error occurred before it was assigned if (chatType === MessageType.Broadcast) { const failedId = messageId ?? `failed-${Date.now()}`; - setMessageState({ type: chatType, channelId: channelValue, messageId: failedId, newState: MessageState.Failed }); + setMessageState({ + type: chatType, + channelId: channelValue, + messageId: failedId, + newState: MessageState.Failed, + }); } else { // MessageType.Direct const failedId = messageId ?? `failed-${Date.now()}`; - setMessageState({ type: chatType, nodeA: getMyNodeNum(), nodeB: activeChat, messageId: failedId, newState: MessageState.Failed }); + setMessageState({ + type: chatType, + nodeA: getMyNodeNum(), + nodeB: activeChat, + messageId: failedId, + newState: MessageState.Failed, + }); } } }, [activeChat, chatType, connection, getMyNodeNum, setMessageState]); @@ -100,7 +152,11 @@ export const MessagesPage = () => { case MessageType.Direct: return ( ); default: @@ -110,7 +166,7 @@ export const MessagesPage = () => {

); } - } + }; const leftSidebar = useMemo(() => ( @@ -119,72 +175,108 @@ export const MessagesPage = () => { { setChatType(MessageType.Broadcast); setActiveChat(channel.index); resetUnread(channel.index); }} > - + ))} - ), [filteredChannels, unreadCounts, activeChat, chatType, isCollapsed, setActiveChat, setChatType, resetUnread]); - - const rightSidebar = useMemo(() => ( - - -
- {filteredNodes()?.map((node) => ( - 0 ? node.unreadCount : undefined} - active={activeChat === node.num && chatType === MessageType.Direct} - onClick={() => { - setChatType(MessageType.Direct); - setActiveChat(node.num); - resetUnread(node.num); - }}> - - - ))} -
-
- ), [filteredNodes, searchTerm, activeChat, chatType, setActiveChat, setChatType, resetUnread, hasNodeError]); + ), [ + filteredChannels, + unreadCounts, + activeChat, + chatType, + isCollapsed, + setActiveChat, + setChatType, + resetUnread, + ]); + + const rightSidebar = useMemo( + () => ( + + +
+ {filteredNodes()?.map((node) => ( + 0 ? node.unreadCount : undefined} + active={activeChat === node.num && + chatType === MessageType.Direct} + onClick={() => { + setChatType(MessageType.Direct); + setActiveChat(node.num); + resetUnread(node.num); + }} + > + + + ))} +
+
+ ), + [ + filteredNodes, + searchTerm, + activeChat, + chatType, + setActiveChat, + setChatType, + resetUnread, + hasNodeError, + ], + ); return ( { {renderChatContent()}
- {(isBroadcast || isDirect) ? ( - - ) : ( -
Select a chat to send a message.
- )} + {(isBroadcast || isDirect) + ? ( + + ) + : ( +
+ Select a chat to send a message. +
+ )}
); }; -export default MessagesPage; \ No newline at end of file +export default MessagesPage;