Browse Source

feat: added router

pull/640/head
Dan Ditomaso 1 year ago
parent
commit
ae3d0711f6
  1. 2
      deno.json
  2. 205
      deno.lock
  3. 3
      package.json
  4. 9
      src/App.tsx
  5. 27
      src/PageRouter.tsx
  6. 14
      src/components/CommandPalette/index.tsx
  7. 11
      src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx
  8. 6
      src/components/PageComponents/Map/NodeDetail.tsx
  9. 2
      src/components/PageComponents/Messages/MessageItem.tsx
  10. 41
      src/components/Sidebar.tsx
  11. 13
      src/core/stores/deviceStore.ts
  12. 18
      src/index.tsx
  13. 59
      src/routeTree.gen.ts
  14. 60
      src/routes.tsx

2
deno.json

@ -31,12 +31,14 @@
},
"fmt": {
"exclude": [
"src/*.gen.ts",
"*.test.ts",
"*.test.tsx"
]
},
"lint": {
"exclude": [
"src/*.gen.ts",
"*.test.ts",
"*.test.tsx"
],

205
deno.lock

@ -27,6 +27,9 @@
"npm:@radix-ui/react-toggle-group@^1.1.9": "1.1.10_@[email protected]_@[email protected]__@[email protected][email protected][email protected][email protected]",
"npm:@radix-ui/react-tooltip@^1.2.4": "1.2.4_@[email protected]_@[email protected]__@[email protected][email protected][email protected][email protected]",
"npm:@tailwindcss/postcss@^4.1.5": "4.1.5",
"npm:@tanstack/react-router@^1.120.15": "[email protected][email protected][email protected]",
"npm:@tanstack/router-devtools@^1.120.15": "1.120.15_@[email protected][email protected][email protected][email protected][email protected][email protected][email protected]",
"npm:@tanstack/router-plugin@^1.120.15": "1.120.15_@[email protected][email protected][email protected][email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected][email protected]_@[email protected]",
"npm:@testing-library/jest-dom@^6.6.3": "6.6.3",
"npm:@testing-library/react@^16.3.0": "16.3.0_@[email protected]_@[email protected]_@[email protected]__@[email protected][email protected][email protected][email protected]",
"npm:@testing-library/user-event@^14.6.1": "14.6.1_@[email protected]",
@ -366,6 +369,20 @@
"@babel/helper-plugin-utils"
]
},
"@babel/[email protected]_@[email protected]": {
"integrity": "sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==",
"dependencies": [
"@babel/core",
"@babel/helper-plugin-utils"
]
},
"@babel/[email protected]_@[email protected]": {
"integrity": "sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==",
"dependencies": [
"@babel/core",
"@babel/helper-plugin-utils"
]
},
"@babel/[email protected]_@[email protected]": {
"integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==",
"dependencies": [
@ -2341,6 +2358,126 @@
"tailwindcss"
]
},
"@tanstack/[email protected]": {
"integrity": "sha512-K7JJNrRVvyjAVnbXOH2XLRhFXDkeP54Kt2P4FR1Kl2KDGlIbkua5VqZQD2rot3qaDrpufyUa63nuLai1kOLTsQ=="
},
"@tanstack/[email protected]_@[email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected][email protected]": {
"integrity": "sha512-5KcUXc3fkiLo/6Y56gOM3JqmYXG1ElIH2iyUWuG5IlcegLrpXhu4OBQ+8Q4+62CD0OKy0ifUDyemrCOAEOfCvw==",
"dependencies": [
"@tanstack/react-router",
"@tanstack/router-devtools-core",
"react",
"react-dom",
"solid-js"
]
},
"@tanstack/[email protected][email protected][email protected][email protected]": {
"integrity": "sha512-apzBmXh4pHwqUGU3kD8y2FJMi7rVoUbRxh5oV7v8kEb6Aq5Xpdo+OcpThw8h/M2zv7v4Ef8IoY6WFCKKu3HBjQ==",
"dependencies": [
"@tanstack/history",
"@tanstack/react-store",
"@tanstack/router-core",
"[email protected]",
"react",
"react-dom",
"tiny-invariant",
"tiny-warning"
]
},
"@tanstack/[email protected][email protected][email protected][email protected]": {
"integrity": "sha512-qUTEKdId6QPWGiWyKAPf/gkN29scEsz6EUSJ0C3HgLMgaqTAyBsQ2sMCfGVcqb+kkhEXAdjleCgH6LAPD6f2sA==",
"dependencies": [
"@tanstack/store",
"react",
"react-dom",
"use-sync-external-store"
]
},
"@tanstack/[email protected]": {
"integrity": "sha512-soLj+mEuvSxAVFK/3b85IowkkvmSuQL6J0RSIyKJFGFgy0CmUzpcBGEO99+JNWvvvzHgIoY4F4KtLIN+rvFSFA==",
"dependencies": [
"@tanstack/history",
"@tanstack/store",
"tiny-invariant"
]
},
"@tanstack/[email protected]_@[email protected][email protected][email protected][email protected]": {
"integrity": "sha512-AT9obPHKpJqnHMbwshozSy6sApg5LchiAll3blpS3MMDybUCidYHrdhe9MZJLmlC99IQiEGmuZERP3VRcuPNHg==",
"dependencies": [
"@tanstack/router-core",
"clsx",
"goober",
"solid-js",
"tiny-invariant"
]
},
"@tanstack/[email protected]_@[email protected][email protected][email protected][email protected][email protected][email protected][email protected]": {
"integrity": "sha512-u7KbvupWSppoEUYuhCBzmWkd1hcODzHhvGIuWZKoQO9q/qeNY5XptbzGqBSUooXyoF4T/pAdCRILF5zFIqexJw==",
"dependencies": [
"@tanstack/react-router",
"@tanstack/react-router-devtools",
"clsx",
"goober",
"react",
"react-dom"
]
},
"@tanstack/[email protected]_@[email protected][email protected][email protected][email protected][email protected][email protected][email protected]": {
"integrity": "sha512-QwZ0rNXxzgOEUDRRAEWVjofKxuxSMIYEdYC3z20k6a7jkLC6pnlCORFx41Vf4xVCO6eElqlrUKXWLTleYSsvQw==",
"dependencies": [
"@tanstack/react-router",
"@tanstack/virtual-file-routes",
"prettier",
"tsx",
"zod"
],
"optionalPeers": [
"@tanstack/react-router"
]
},
"@tanstack/[email protected]_@[email protected][email protected][email protected][email protected][email protected]__@[email protected][email protected]_@[email protected][email protected][email protected][email protected]_@[email protected]": {
"integrity": "sha512-ARuuPRKO5HzN3V0LzmkIGm0e447t5VCy2ijbUnzd08KjcJm3lG221ViC2qI+vTom1zp6yeNZHfJW1LBh1yLrTw==",
"dependencies": [
"@babel/core",
"@babel/plugin-syntax-jsx",
"@babel/plugin-syntax-typescript",
"@babel/template",
"@babel/traverse",
"@babel/types",
"@tanstack/react-router",
"@tanstack/router-core",
"@tanstack/router-generator",
"@tanstack/router-utils",
"@tanstack/virtual-file-routes",
"@types/babel__core",
"@types/babel__template",
"@types/babel__traverse",
"babel-dead-code-elimination",
"chokidar",
"unplugin",
"vite",
"zod"
],
"optionalPeers": [
"@tanstack/react-router",
"vite"
]
},
"@tanstack/[email protected]": {
"integrity": "sha512-Dng4y+uLR9b5zPGg7dHReHOTHQa6x+G6nCoZshsDtWrYsrdCcJEtLyhwZ5wG8OyYS6dVr/Cn+E5Bd2b6BhJ89w==",
"dependencies": [
"@babel/generator",
"@babel/parser",
"ansis",
"diff"
]
},
"@tanstack/[email protected]": {
"integrity": "sha512-PjUQKXEXhLYj2X5/6c1Xn/0/qKY0IVFxTJweopRfF26xfjVyb14yALydJrHupDh3/d+1WKmfEgZPBVCmDkzzwg=="
},
"@tanstack/[email protected]": {
"integrity": "sha512-XLUh1Py3AftcERrxkxC5Y5m5mfllRH3YR6YVlyjFgI2Tc2Ssy2NKmQFQIafoxfW459UJ8Dn81nWKETEIJifE4g=="
},
"@testing-library/[email protected]": {
"integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==",
"dependencies": [
@ -3972,6 +4109,9 @@
"[email protected]": {
"integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA=="
},
"[email protected]": {
"integrity": "sha512-0qWUglt9JEqLFr3w1I1pbrChn1grhaiAR2ocX1PP/flRmxgtwTzPFFFnfIlD6aMOLQZgSuCRlidD70lvx8yhzg=="
},
"[email protected]": {
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dependencies": [
@ -4071,6 +4211,15 @@
"possible-typed-array-names"
]
},
"[email protected]": {
"integrity": "sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==",
"dependencies": [
"@babel/core",
"@babel/parser",
"@babel/traverse",
"@babel/types"
]
},
"[email protected]_@[email protected]": {
"integrity": "sha512-3sX/eOms8kd3q2KZ6DAhKPc0dgm525Gqq5NtWKZ7QYYZEv57OQ54KtblzJzH1lQF/eQxO8KjWGIK9IPUJNus5g==",
"dependencies": [
@ -4559,6 +4708,9 @@
"[email protected]": {
"integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ=="
},
"[email protected]": {
"integrity": "sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw=="
},
"[email protected]": {
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
"dependencies": [
@ -5018,6 +5170,12 @@
"gopd"
]
},
"[email protected][email protected]": {
"integrity": "sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==",
"dependencies": [
"csstype"
]
},
"[email protected]": {
"integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="
},
@ -5937,6 +6095,10 @@
"[email protected]": {
"integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw=="
},
"[email protected]": {
"integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==",
"bin": true
},
"[email protected]": {
"integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg=="
},
@ -6358,6 +6520,15 @@
"randombytes"
]
},
"[email protected][email protected]": {
"integrity": "sha512-0QvCV2lM3aj/U3YozDiVwx9zpH0q8A60CTWIv4Jszj/givcudPb48B+rkU5D51NJ0pTpweGMttHjboPa9/zoIQ==",
"dependencies": [
"seroval"
]
},
"[email protected]": {
"integrity": "sha512-RbcPH1n5cfwKrru7v7+zrZvjLurgHhGyso3HTyGtRivGWgYjbOmGuivCQaORNELjNONoK35nj28EoWul9sb1zQ=="
},
"[email protected]": {
"integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
"dependencies": [
@ -6465,6 +6636,14 @@
"[email protected]": {
"integrity": "sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig=="
},
"[email protected][email protected]": {
"integrity": "sha512-/saTKi8iWEM233n5OSi1YHCCuh66ZIQ7aK2hsToPe4tqGm7qAejU1SwNuTPivbWAYq7SjuHVVYxxuZQNRbICiw==",
"dependencies": [
"csstype",
"seroval",
"seroval-plugins"
]
},
"[email protected]": {
"integrity": "sha512-umMGhjPeHAI6YjABoSTrFp2zaBtXBej1a0yKkuMUyjjqu6FJsTF+JYwCswWDg+zJfk/5npWUUbd33HH/WLzpaA=="
},
@ -6720,6 +6899,12 @@
"setimmediate"
]
},
"[email protected]": {
"integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg=="
},
"[email protected]": {
"integrity": "sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA=="
},
"[email protected]": {
"integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="
},
@ -6909,6 +7094,14 @@
"[email protected]": {
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw=="
},
"[email protected]": {
"integrity": "sha512-RyWSb5AHmGtjjNQ6gIlA67sHOsWpsbWpwDokLwTcejVdOjEkJZh7QKu14J00gDDVSh8kGH4KYC/TNBceXFZhtw==",
"dependencies": [
"acorn",
"[email protected]",
"webpack-virtual-modules"
]
},
"[email protected]": {
"integrity": "sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg=="
},
@ -6951,6 +7144,12 @@
"@types/react"
]
},
"[email protected][email protected]": {
"integrity": "sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==",
"dependencies": [
"react"
]
},
"[email protected]": {
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw=="
},
@ -7100,6 +7299,9 @@
"[email protected]": {
"integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g=="
},
"[email protected]": {
"integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ=="
},
"[email protected]": {
"integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q=="
},
@ -7390,6 +7592,9 @@
"npm:@radix-ui/react-toggle-group@^1.1.9",
"npm:@radix-ui/react-tooltip@^1.2.4",
"npm:@tailwindcss/postcss@^4.1.5",
"npm:@tanstack/react-router@^1.120.15",
"npm:@tanstack/router-devtools@^1.120.15",
"npm:@tanstack/router-plugin@^1.120.15",
"npm:@testing-library/jest-dom@^6.6.3",
"npm:@testing-library/react@^16.3.0",
"npm:@testing-library/user-event@^14.6.1",

3
package.json

@ -57,6 +57,8 @@
"@radix-ui/react-toast": "^1.2.11",
"@radix-ui/react-toggle-group": "^1.1.9",
"@radix-ui/react-tooltip": "^1.2.4",
"@tanstack/react-router": "^1.120.15",
"@tanstack/router-devtools": "^1.120.15",
"@turf/turf": "^7.2.0",
"base64-js": "^1.5.1",
"class-validator": "^0.14.2",
@ -87,6 +89,7 @@
},
"devDependencies": {
"@tailwindcss/postcss": "^4.1.5",
"@tanstack/router-plugin": "^1.120.15",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.3.0",
"@testing-library/user-event": "^14.6.1",

9
src/App.tsx

@ -1,5 +1,4 @@
import { DeviceWrapper } from "@app/DeviceWrapper.tsx";
import { PageRouter } from "@app/PageRouter.tsx";
import { DialogManager } from "@components/Dialog/DialogManager.tsx";
import { NewDeviceDialog } from "@components/Dialog/NewDeviceDialog.tsx";
import { KeyBackupReminder } from "@components/KeyBackupReminder.tsx";
@ -8,15 +7,15 @@ import Footer from "@components/UI/Footer.tsx";
import { useAppStore } from "@core/stores/appStore.ts";
import { useDeviceStore } from "@core/stores/deviceStore.ts";
import { Dashboard } from "@pages/Dashboard/index.tsx";
import type { JSX } from "react";
import { ErrorBoundary } from "react-error-boundary";
import { ErrorPage } from "@components/UI/ErrorPage.tsx";
import { MapProvider } from "react-map-gl/maplibre";
import { CommandPalette } from "@components/CommandPalette/index.tsx";
import { SidebarProvider } from "@core/stores/sidebarStore.tsx";
import { useTheme } from "@core/hooks/useTheme.ts";
import { Outlet } from "@tanstack/react-router";
export const App = (): JSX.Element => {
export function App() {
const { getDevice } = useDeviceStore();
const { selectedDevice, setConnectDialogOpen, connectDialogOpen } =
useAppStore();
@ -49,7 +48,7 @@ export const App = (): JSX.Element => {
<KeyBackupReminder />
<CommandPalette />
<MapProvider>
<PageRouter />
<Outlet />
</MapProvider>
</div>
)
@ -65,4 +64,4 @@ export const App = (): JSX.Element => {
</DeviceWrapper>
</ErrorBoundary>
);
};
}

27
src/PageRouter.tsx

@ -1,27 +0,0 @@
import MapPage from "@app/pages/Map/index.tsx";
import { useDevice } from "@core/stores/deviceStore.ts";
import ChannelsPage from "@pages/Channels.tsx";
import ConfigPage from "@pages/Config/index.tsx";
import MessagesPage from "@pages/Messages.tsx";
import NodesPage from "@pages/Nodes.tsx";
import { ErrorBoundary } from "react-error-boundary";
import { ErrorPage } from "@components/UI/ErrorPage.tsx";
export const ErrorBoundaryWrapper = ({
children,
}: { children: React.ReactNode }) => (
<ErrorBoundary FallbackComponent={ErrorPage}>{children}</ErrorBoundary>
);
export const PageRouter = () => {
const { activePage } = useDevice();
return (
<ErrorBoundary FallbackComponent={ErrorPage}>
{activePage === "messages" && <MessagesPage />}
{activePage === "map" && <MapPage />}
{activePage === "config" && <ConfigPage />}
{activePage === "channels" && <ChannelsPage />}
{activePage === "nodes" && <NodesPage />}
</ErrorBoundary>
);
};

14
src/components/CommandPalette/index.tsx

@ -35,6 +35,7 @@ import { Avatar } from "@components/UI/Avatar.tsx";
import { cn } from "@core/utils/cn.ts";
import { useTranslation } from "react-i18next";
import { usePinnedItems } from "@core/hooks/usePinnedItems.ts";
import { useNavigate } from "@tanstack/react-router";
export interface Group {
id: string;
@ -63,11 +64,12 @@ export const CommandPalette = () => {
setSelectedDevice,
} = useAppStore();
const { getDevices } = useDeviceStore();
const { setDialogOpen, setActivePage, getNode, connection } = useDevice();
const { setDialogOpen, getNode, connection } = useDevice();
const { pinnedItems, togglePinnedItem } = usePinnedItems({
storageName: "pinnedCommandMenuGroups",
});
const { t } = useTranslation("commandPalette");
const navigate = useNavigate({ from: "/" });
const groups: Group[] = [
{
@ -79,21 +81,21 @@ export const CommandPalette = () => {
label: t("goto.command.messages"),
icon: MessageSquareIcon,
action() {
setActivePage("messages");
navigate({ to: "/messages" });
},
},
{
label: t("goto.command.map"),
icon: MapIcon,
action() {
setActivePage("map");
navigate({ to: "/map" });
},
},
{
label: t("goto.command.config"),
icon: SettingsIcon,
action() {
setActivePage("config");
navigate({ to: "/config" });
},
tags: ["settings"],
},
@ -101,14 +103,14 @@ export const CommandPalette = () => {
label: t("goto.command.channels"),
icon: LayersIcon,
action() {
setActivePage("channels");
navigate({ to: "/channels" });
},
},
{
label: t("goto.command.nodes"),
icon: UsersIcon,
action() {
setActivePage("nodes");
navigate({ to: "/nodes" });
},
},
],

11
src/components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx

@ -1,5 +1,4 @@
import { useEffect, useState } from "react";
import { useAppStore } from "@core/stores/appStore.ts";
import { useDevice } from "@core/stores/deviceStore.ts";
import {
@ -12,8 +11,8 @@ import { DeviceImage } from "@components/generic/DeviceImage.tsx";
import { TimeAgo } from "@components/generic/TimeAgo.tsx";
import { Uptime } from "@components/generic/Uptime.tsx";
import { toast } from "@core/hooks/useToast.ts";
import { useFavoriteNode } from "../../../core/hooks/useFavoriteNode.ts";
import { useIgnoreNode } from "../../../core/hooks/useIgnoreNode.ts";
import { useFavoriteNode } from "@core/hooks/useFavoriteNode.ts";
import { useIgnoreNode } from "@core/hooks/useIgnoreNode.ts";
import { cn } from "@core/utils/cn.ts";
import {
@ -49,6 +48,7 @@ import {
} from "@components/UI/Tooltip.tsx";
import { Separator } from "@components/UI/Seperator.tsx";
import { useTranslation } from "react-i18next";
import { useNavigate } from "@tanstack/react-router";
export interface NodeDetailsDialogProps {
open: boolean;
@ -60,7 +60,8 @@ export const NodeDetailsDialog = ({
onOpenChange,
}: NodeDetailsDialogProps) => {
const { t } = useTranslation("dialog");
const { setDialogOpen, connection, setActivePage, getNode } = useDevice();
const { setDialogOpen, connection, getNode } = useDevice();
const navigate = useNavigate();
const { setNodeNumToBeRemoved, nodeNumDetails } = useAppStore();
const { setChatType, setActiveChat } = useMessageStore();
const { updateFavorite } = useFavoriteNode();
@ -88,7 +89,7 @@ export const NodeDetailsDialog = ({
setChatType(MessageType.Direct);
setActiveChat(node.num);
setActivePage("messages");
navigate({ to: "/messages" });
}
function handleRequestPosition() {

6
src/components/PageComponents/Map/NodeDetail.tsx

@ -22,13 +22,13 @@ import {
TooltipProvider,
TooltipTrigger,
} from "@radix-ui/react-tooltip";
import { useDevice } from "@core/stores/deviceStore.ts";
import {
MessageType,
useMessageStore,
} from "@core/stores/messageStore/index.ts";
import BatteryStatus from "@components/BatteryStatus.tsx";
import { useTranslation } from "react-i18next";
import { useNavigate } from "@tanstack/react-router";
export interface NodeDetailProps {
node: ProtobufType.Mesh.NodeInfo;
@ -36,8 +36,8 @@ export interface NodeDetailProps {
export const NodeDetail = ({ node }: NodeDetailProps) => {
const { setChatType, setActiveChat } = useMessageStore();
const navigate = useNavigate();
const { t } = useTranslation("nodes");
const { setActivePage } = useDevice();
const name = node.user?.longName ?? t("unknown.shortName");
const shortName = node.user?.shortName ?? t("unknown.shortName");
const hwModel = node.user?.hwModel ?? 0;
@ -52,7 +52,7 @@ export const NodeDetail = ({ node }: NodeDetailProps) => {
function handleDirectMessage() {
setChatType(MessageType.Direct);
setActiveChat(node.num);
setActivePage("messages");
navigate({ to: "/messages" });
}
return (

2
src/components/PageComponents/Messages/MessageItem.tsx

@ -18,7 +18,7 @@ import {
import { Protobuf, Types } from "@meshtastic/js";
import { Message } from "@core/stores/messageStore/types.ts";
import { useTranslation } from "react-i18next";
// import { MessageActionsMenu } from "@components/PageComponents/Messages/MessageActionsMenu.tsx"; // Uncomment if needed later
// import { MessageActionsMenu } from "@components/PageComponents/Messages/MessageActionsMenu.tsx"; // TODO: Uncomment when actions menu is implemented
interface MessageStatusInfo {
displayText: string;

41
src/components/Sidebar.tsx

@ -20,6 +20,7 @@ import { useAppStore } from "@core/stores/appStore.ts";
import { SidebarButton } from "@components/UI/Sidebar/SidebarButton.tsx";
import { useTranslation } from "react-i18next";
import { DeviceInfoPanel } from "./DeviceInfoPanel.tsx";
import { useLocation, useNavigate } from "@tanstack/react-router";
export interface SidebarProps {
children?: React.ReactNode;
@ -69,15 +70,19 @@ export const Sidebar = ({ children }: SidebarProps) => {
getNode,
getNodesLength,
metadata,
activePage,
unreadCounts,
setActivePage,
setDialogOpen,
} = useDevice();
const { setCommandPaletteOpen } = useAppStore();
const myNode = getNode(hardware.myNodeNum);
const { isCollapsed } = useSidebar();
const { t } = useTranslation("ui");
const navigate = useNavigate({ from: "/" });
const pathname = useLocation({
select: (location) => location.pathname.replace(/^\//, ""),
});
const myMetadata = metadata.get(0);
const numUnread = [...unreadCounts.values()].reduce((sum, v) => sum + v, 0);
@ -162,21 +167,23 @@ export const Sidebar = ({ children }: SidebarProps) => {
label={t("navigation.title")}
className="mt-4 px-0"
>
{pages.map((link) => (
<SidebarButton
key={link.name}
count={link.count}
label={link.name}
Icon={link.icon}
onClick={() => {
if (myNode !== undefined) {
setActivePage(link.page);
}
}}
active={link.page === activePage}
disabled={myNode === undefined}
/>
))}
{pages.map((link) => {
return (
<SidebarButton
key={link.name}
count={link.count}
label={link.name}
Icon={link.icon}
onClick={() => {
if (myNode !== undefined) {
navigate({ to: `/${link.page}` });
}
}}
active={link.page === pathname}
disabled={myNode === undefined}
/>
);
})}
</SidebarSection>
<div

13
src/core/stores/deviceStore.ts

@ -35,7 +35,6 @@ export interface Device {
>;
nodeErrors: Map<number, NodeError>;
connection?: MeshDevice;
activePage: Page;
activeNode: number;
waypoints: Protobuf.Mesh.Waypoint[];
pendingSettingsChanges: boolean;
@ -63,7 +62,6 @@ export interface Device {
setWorkingConfig: (config: Protobuf.Config.Config) => void;
setWorkingModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void;
setHardware: (hardware: Protobuf.Mesh.MyNodeInfo) => void;
setActivePage: (page: Page) => void;
setActiveNode: (node: number) => void;
setPendingSettingsChanges: (state: boolean) => void;
addChannel: (channel: Protobuf.Channel.Channel) => void;
@ -129,7 +127,6 @@ export const useDeviceStore = createStore<PrivateDeviceState>((set, get) => ({
metadata: new Map(),
traceroutes: new Map(),
connection: undefined,
activePage: "messages",
activeNode: 0,
waypoints: [],
dialog: {
@ -318,16 +315,6 @@ export const useDeviceStore = createStore<PrivateDeviceState>((set, get) => ({
}),
);
},
setActivePage: (page) => {
set(
produce<DeviceState>((draft) => {
const device = draft.devices.get(id);
if (device) {
device.activePage = page;
}
}),
);
},
setPendingSettingsChanges: (state) => {
set(
produce<DeviceState>((draft) => {

18
src/index.tsx

@ -3,19 +3,29 @@ import { enableMapSet } from "immer";
import "maplibre-gl/dist/maplibre-gl.css";
import { StrictMode, Suspense } from "react";
import { createRoot } from "react-dom/client";
import { App } from "@app/App.tsx";
import "./i18n/config.ts";
import { createRouter, RouterProvider } from "@tanstack/react-router";
import { routeTree } from "@app/routes.tsx";
declare module "@tanstack/react-router" {
interface Register {
router: ReturnType<typeof createRouter>;
}
}
const container = document.getElementById("root") as HTMLElement;
const root = createRoot(container);
enableMapSet();
const router = createRouter({
routeTree,
});
root.render(
<StrictMode>
<Suspense fallback={null}>
<App />
</Suspense>,
<RouterProvider router={router} />
</Suspense>
</StrictMode>,
);

59
src/routeTree.gen.ts

@ -0,0 +1,59 @@
/* eslint-disable */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
// Import Routes
import { Route as rootRoute } from './routes/__root'
// Create/Update Routes
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {}
}
// Create and export the route tree
export interface FileRoutesByFullPath {}
export interface FileRoutesByTo {}
export interface FileRoutesById {
__root__: typeof rootRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: never
fileRoutesByTo: FileRoutesByTo
to: never
id: '__root__'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {}
const rootRouteChildren: RootRouteChildren = {}
export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
/* ROUTE_MANIFEST_START
{
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": []
}
}
}
ROUTE_MANIFEST_END */

60
src/routes.tsx

@ -0,0 +1,60 @@
import { createRoute } from "@tanstack/react-router";
import { Dashboard } from "@pages/Dashboard/index.tsx";
import MessagesPage from "@pages/Messages.tsx";
import MapPage from "@pages/Map/index.tsx";
import ConfigPage from "@pages/Config/index.tsx";
import ChannelsPage from "@pages/Channels.tsx";
import NodesPage from "@pages/Nodes.tsx";
import { createRootRoute } from "@tanstack/react-router";
import { App } from "./App.tsx";
const rootRoute = createRootRoute({
component: App,
});
const indexRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/",
component: Dashboard,
});
const messagesRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/messages",
component: MessagesPage,
});
const mapRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/map",
component: MapPage,
});
const configRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/config",
component: ConfigPage,
});
const channelsRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/channels",
component: ChannelsPage,
});
const nodesRoute = createRoute({
getParentRoute: () => rootRoute,
path: "/nodes",
component: NodesPage,
});
export const routeTree = rootRoute.addChildren([
indexRoute,
messagesRoute,
mapRoute,
configRoute,
channelsRoute,
nodesRoute,
]);
export { rootRoute };
Loading…
Cancel
Save