diff --git a/package.json b/package.json index cc2b4f68..d96ac224 100644 --- a/package.json +++ b/package.json @@ -14,13 +14,12 @@ }, "dependencies": { "@emeraldpay/hashicon-react": "^0.5.2", - "@meshtastic/meshtasticjs": "^0.6.45", + "@meshtastic/meshtasticjs": "^0.6.46", "@reduxjs/toolkit": "^1.7.2", "@tippyjs/react": "^4.2.6", "base64-js": "^1.5.1", "cuid": "^2.1.8", "framer-motion": "^6.2.6", - "graphql-request": "^4.0.0", "mapbox-gl": "^2.7.0", "react": "^17.0.2", "react-dom": "^17.0.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a3bf13e9..8febba1b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -3,7 +3,7 @@ lockfileVersion: 5.3 specifiers: '@emeraldpay/hashicon-react': ^0.5.2 '@hookform/devtools': ^4.0.2 - '@meshtastic/meshtasticjs': ^0.6.45 + '@meshtastic/meshtasticjs': ^0.6.46 '@reduxjs/toolkit': ^1.7.2 '@tippyjs/react': ^4.2.6 '@types/mapbox-gl': ^2.6.1 @@ -28,7 +28,6 @@ specifiers: eslint-plugin-react: ^7.28.0 eslint-plugin-react-hooks: ^4.3.0 framer-motion: ^6.2.6 - graphql-request: ^4.0.0 gzipper: ^7.0.0 mapbox-gl: ^2.7.0 postcss: ^8.4.6 @@ -62,13 +61,12 @@ specifiers: dependencies: '@emeraldpay/hashicon-react': 0.5.2 - '@meshtastic/meshtasticjs': 0.6.45 + '@meshtastic/meshtasticjs': 0.6.46 '@reduxjs/toolkit': 1.7.2_react-redux@7.2.6+react@17.0.2 '@tippyjs/react': 4.2.6_react-dom@17.0.2+react@17.0.2 base64-js: 1.5.1 cuid: 2.1.8 framer-motion: 6.2.6_react-dom@17.0.2+react@17.0.2 - graphql-request: 4.0.0 mapbox-gl: 2.7.0 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 @@ -1638,8 +1636,8 @@ packages: engines: {node: '>=6.0.0'} dev: false - /@meshtastic/meshtasticjs/0.6.45: - resolution: {integrity: sha512-icAGMofpQ3hYqWhjYMLqMyhb0Xtk3GozEgOXScFTKVOaecDY0XIJmuvoBDfgD2lxNxDDPr0Dj77js+3JGxTcRg==} + /@meshtastic/meshtasticjs/0.6.46: + resolution: {integrity: sha512-XOaQz75kYDNvv1zK9KXy5te8V9AEyVXWK0JvK3v1v+WqAJ9UNvnNcaQTRsJBPG2elmE3cQkfEz+WfBus2wve8g==} dependencies: '@protobuf-ts/runtime': 2.2.2 sub-events: 1.8.9 @@ -2312,10 +2310,6 @@ packages: resolution: {integrity: sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=} dev: true - /asynckit/0.4.0: - resolution: {integrity: sha1-x57Zf380y48robyXkLzDZkdLS3k=} - dev: false - /at-least-node/1.0.0: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} @@ -2578,13 +2572,6 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: true - /combined-stream/1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - /commander/2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true @@ -2648,14 +2635,6 @@ packages: yaml: 1.10.2 dev: true - /cross-fetch/3.1.5: - resolution: {integrity: sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw==} - dependencies: - node-fetch: 2.6.7 - transitivePeerDependencies: - - encoding - dev: false - /cross-spawn/7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} engines: {node: '>= 8'} @@ -2827,11 +2806,6 @@ packages: resolution: {integrity: sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=} dev: true - /delayed-stream/1.0.0: - resolution: {integrity: sha1-3zrhmayt+31ECqrgsp4icrJOxhk=} - engines: {node: '>=0.4.0'} - dev: false - /detective/5.2.0: resolution: {integrity: sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==} engines: {node: '>=0.8.0'} @@ -3594,11 +3568,6 @@ packages: engines: {node: '>=0.10.0'} dev: true - /extract-files/9.0.0: - resolution: {integrity: sha512-CvdFfHkC95B4bBBk36hcEmvdR2awOdhhVUYH6S/zrVj3477zven/fJMYg7121h4T1xHZC+tetUpubpAhxwI7hQ==} - engines: {node: ^10.17.0 || ^12.0.0 || >= 13.7.0} - dev: false - /fast-deep-equal/3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true @@ -3713,15 +3682,6 @@ packages: resolution: {integrity: sha1-C+4AUBiusmDQo6865ljdATbsG5k=} dev: true - /form-data/3.0.1: - resolution: {integrity: sha512-RHkBKtLWUVwd7SqRIvCZMEvAMoGUp0XU+seQiZejj0COz3RI3hWP4sCv3gZWWLjJTd7rGwcsF5eKZGii0r/hbg==} - engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - mime-types: 2.1.34 - dev: false - /fraction.js/4.1.3: resolution: {integrity: sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==} dev: true @@ -3882,18 +3842,6 @@ packages: resolution: {integrity: sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==} dev: true - /graphql-request/4.0.0: - resolution: {integrity: sha512-cdqQLCXlBGkaLdkLYRl4LtkwaZU6TfpE7/tnUQFl3wXfUPWN74Ov+Q61VuIh+AltS789YfGB6whghmCmeXLvTw==} - peerDependencies: - graphql: 14 - 16 - dependencies: - cross-fetch: 3.1.5 - extract-files: 9.0.0 - form-data: 3.0.1 - transitivePeerDependencies: - - encoding - dev: false - /grid-index/1.1.0: resolution: {integrity: sha512-HZRwumpOGUrHyxO5bqKZL0B0GlUpwtCAzZ42sgxUPniu33R1LSFH5yrIcBCHjkctCAh3mtWKcKd9J4vDDdeVHA==} dev: false @@ -4489,18 +4437,6 @@ packages: picomatch: 2.3.1 dev: true - /mime-db/1.51.0: - resolution: {integrity: sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==} - engines: {node: '>= 0.6'} - dev: false - - /mime-types/2.1.34: - resolution: {integrity: sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==} - engines: {node: '>= 0.6'} - dependencies: - mime-db: 1.51.0 - dev: false - /mimic-fn/2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -4562,18 +4498,6 @@ packages: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} dev: true - /node-fetch/2.6.7: - resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - dependencies: - whatwg-url: 5.0.0 - dev: false - /node-modules-regexp/1.0.0: resolution: {integrity: sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=} engines: {node: '>=0.10.0'} @@ -5858,10 +5782,6 @@ packages: resolution: {integrity: sha1-bkWxJj8gF/oKzH2J14sVuL932jI=} dev: false - /tr46/0.0.3: - resolution: {integrity: sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=} - dev: false - /tr46/1.0.1: resolution: {integrity: sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=} dependencies: @@ -6114,21 +6034,10 @@ packages: defaults: 1.0.3 dev: true - /webidl-conversions/3.0.1: - resolution: {integrity: sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE=} - dev: false - /webidl-conversions/4.0.2: resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} dev: true - /whatwg-url/5.0.0: - resolution: {integrity: sha1-lmRU6HZUYuN2RNNib2dCzotwll0=} - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - dev: false - /whatwg-url/7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} dependencies: diff --git a/src/components/Connection.tsx b/src/components/Connection.tsx index 9e44d846..5dd3a305 100644 --- a/src/components/Connection.tsx +++ b/src/components/Connection.tsx @@ -2,7 +2,6 @@ import React from 'react'; import { AnimatePresence } from 'framer-motion'; -import { Card } from '@app/components/generic/Card'; import { BLE } from '@components/connection/BLE'; import { HTTP } from '@components/connection/HTTP'; import { Serial } from '@components/connection/Serial'; @@ -52,74 +51,72 @@ export const Connection = (): JSX.Element => { {appState.connectionModalOpen && ( { dispatch(closeConnectionModal()); }} > - -
-
-
- { + dispatch(setConnType(parseInt(e.target.value))); + }} + disabled={ + state.deviceStatus === + Types.DeviceStatusEnum.DEVICE_CONNECTED + } + /> + {appState.connType === connType.HTTP && ( + - {appState.connType === connType.HTTP && ( - - )} - {appState.connType === connType.BLE && ( - - )} - {appState.connType === connType.SERIAL && ( - - )} -
-
-
-
- {state.logs - .filter((log) => { - return ![ - Types.Emitter.handleFromRadio, - Types.Emitter.handleMeshPacket, - Types.Emitter.sendPacket, - ].includes(log.emitter); - }) - .map((log, index) => ( -
-
- {log.message} -
-
- ))} -
+ )} + {appState.connType === connType.BLE && ( + + )} + {appState.connType === connType.SERIAL && ( + + )}
-
+
+
+ {state.logs + .filter((log) => { + return ![ + Types.Emitter.handleFromRadio, + Types.Emitter.handleMeshPacket, + Types.Emitter.sendPacket, + ].includes(log.emitter); + }) + .map((log, index) => ( +
+
+ {log.message} +
+
+ ))} +
+
+
)}
diff --git a/src/components/generic/Modal.tsx b/src/components/generic/Modal.tsx index 4caef8c7..b48f35af 100644 --- a/src/components/generic/Modal.tsx +++ b/src/components/generic/Modal.tsx @@ -1,21 +1,23 @@ import type React from 'react'; import { m } from 'framer-motion'; +import { FiX } from 'react-icons/fi'; import { useAppSelector } from '@hooks/useAppSelector'; -type DefaultDivProps = JSX.IntrinsicElements['div']; +import { IconButton } from './button/IconButton'; +import { Card } from './Card'; -export interface ModalProps extends DefaultDivProps { +export interface ModalProps { + title: string; onClose: () => void; children: React.ReactNode; } export const Modal = ({ + title, onClose, children, - className, - ...props }: ModalProps): JSX.Element => { const darkMode = useAppSelector((state) => state.app.darkMode); @@ -32,8 +34,19 @@ export const Modal = ({ > ​ -
- {children} +
+ +
+
+ {title} +
+ } onClick={onClose} /> +
+ {children} +
diff --git a/src/components/menu/BottomNav.tsx b/src/components/menu/BottomNav.tsx index 549288e9..483b62e7 100644 --- a/src/components/menu/BottomNav.tsx +++ b/src/components/menu/BottomNav.tsx @@ -10,6 +10,7 @@ import { FiWifi, FiX, } from 'react-icons/fi'; +import { MdUpgrade } from 'react-icons/md'; import { RiArrowDownLine, RiArrowUpDownLine, @@ -124,19 +125,29 @@ export const BottomNav = (): JSX.Element => {
{ + onClose={(): void => { setShowVersionInfo(false); }} /> - +
{ setShowVersionInfo(true); }} - className="group flex cursor-pointer select-none border-l border-gray-300 p-1 hover:bg-gray-200 dark:border-gray-600 dark:text-white dark:hover:bg-primaryDark" + className={`group flex cursor-pointer select-none border-l border-gray-300 p-1 hover:bg-gray-200 dark:border-gray-600 dark:text-white dark:hover:bg-primaryDark ${ + appState.updateAvaliable ? 'animate-pulse' : '' + }`} > - + {appState.updateAvaliable ? ( + + ) : ( + + )}

{process.env.COMMIT_HASH}

diff --git a/src/components/modals/VersionInfo.tsx b/src/components/modals/VersionInfo.tsx index 4c03cac9..45928505 100644 --- a/src/components/modals/VersionInfo.tsx +++ b/src/components/modals/VersionInfo.tsx @@ -1,59 +1,91 @@ import React from 'react'; import { AnimatePresence } from 'framer-motion'; +import useSWR from 'swr'; +import { setUpdateAvaliable } from '@app/core/slices/appSlice.js'; +import { fetcher } from '@app/core/utils/fetcher.js'; +import { useAppDispatch } from '@app/hooks/useAppDispatch.js'; import { Modal } from '@components/generic/Modal'; -import { Card } from '../generic/Card'; +export interface Commit { + sha: string; + node_id: string; + commit: { + author: string; + committer: string; + message: string; + tree: { + sha: string; + url: string; + }; + url: string; + comment_count: number; + }; + url: string; + html_url: string; + comments_url: string; +} export interface VersionInfoProps { visible: boolean; - onclose: () => void; + onClose: () => void; } export const VersionInfo = ({ visible, - onclose, + onClose, }: VersionInfoProps): JSX.Element => { - // const { data } = useSWR( - // `query { - // repository(owner: "meshtastic", name: "meshtastic-web") { - // ref(qualifiedName: "master") { - // name - // target { - // ... on Commit { - // history(first: 4) { - // edges { - // node { - // abbreviatedOid - // message - // author { - // avatarUrl - // name - // } - // } - // } - // } - // } - // } - // } - // } - // }`, - // fetcher, - // ); + const dispatch = useAppDispatch(); + + const { data } = useSWR( + 'https://api.github.com/repos/meshtastic/meshtastic-web/commits?per_page=10', + fetcher, + { + revalidateOnFocus: false, + }, + ); + + React.useEffect(() => { + if (data) { + const index = data.findIndex( + (commit) => commit.sha.substring(0, 7) === process.env.COMMIT_HASH, + ); + console.log(index); + + if (index === -1 || index > 0) { + dispatch(setUpdateAvaliable(true)); + } + } + }, [data]); return ( {visible && ( { - onclose(); + onClose(); }} > - -
Version Info
- {/* {data?.sha} */} -
+
+ {data && + data.map((commit) => ( +
+
+ {commit.sha.substring(0, 7)} +
+
{commit.commit.message}
+
+ ))} +
)}
diff --git a/src/core/slices/appSlice.ts b/src/core/slices/appSlice.ts index 5727bec7..43942144 100644 --- a/src/core/slices/appSlice.ts +++ b/src/core/slices/appSlice.ts @@ -22,6 +22,7 @@ interface AppState { HTTP: Types.HTTPConnectionParameters; SERIAL: Types.SerialConnectionParameters; }; + updateAvaliable: boolean; } const initialState: AppState = { @@ -41,6 +42,7 @@ const initialState: AppState = { }, SERIAL: {}, }, + updateAvaliable: false, }; export const appSlice = createSlice({ @@ -77,6 +79,9 @@ export const appSlice = createSlice({ state.connectionParams[connType[action.payload.type]] = action.payload.params; }, + setUpdateAvaliable(state, action: PayloadAction) { + state.updateAvaliable = action.payload; + }, }, }); @@ -88,6 +93,7 @@ export const { setCurrentPage, setConnType, setConnectionParams, + setUpdateAvaliable, } = appSlice.actions; export default appSlice.reducer; diff --git a/src/core/utils/fetcher.ts b/src/core/utils/fetcher.ts index 9c5c4dfb..f0ba9a04 100644 --- a/src/core/utils/fetcher.ts +++ b/src/core/utils/fetcher.ts @@ -1,7 +1,7 @@ -export default async function fetcher( +export const fetcher = async ( input: RequestInfo, init?: RequestInit, -): Promise { +): Promise => { const res = await fetch(input, init); return res.json() as Promise; -} +}; diff --git a/src/core/utils/gqlFetcher.ts b/src/core/utils/gqlFetcher.ts deleted file mode 100644 index 2da6aa52..00000000 --- a/src/core/utils/gqlFetcher.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { request } from 'graphql-request'; - -export default async function gqlFetcher( - url: string, - query?: string, -): Promise { - // const res = await fetch(input, init); - return await request(url, query); -} diff --git a/src/pages/Extensions/FileBrowser.tsx b/src/pages/Extensions/FileBrowser.tsx index 547a422f..56323b1b 100644 --- a/src/pages/Extensions/FileBrowser.tsx +++ b/src/pages/Extensions/FileBrowser.tsx @@ -4,7 +4,7 @@ import { AnimatePresence, m } from 'framer-motion'; import useSWR from 'swr'; import { Card } from '@app/components/generic/Card'; -import fetcher from '@core/utils/fetcher'; +import { fetcher } from '@core/utils/fetcher'; import { useAppSelector } from '@hooks/useAppSelector'; export interface File { diff --git a/todo.txt b/todo.txt deleted file mode 100644 index 6432808b..00000000 --- a/todo.txt +++ /dev/null @@ -1,18 +0,0 @@ -Add desctiptions to form elements (below on mobile, to the right on desktop) -add default value to undefined protobufs, (omit if default to keep them small (only for ota packets)) -add input validation min,max etc -maybe make channel editor acordion? -add url routing for settings tabs -add loading blur to card (prop) -form still considered dirty after save -form prefix should be located in the input (absolute?) -form suffix should focus input -reset store on new connection -redux actions seem to be dispatched twice -add qr generator in channel editor -no save button for channel config (bw,sf,cr,tx etc) -should reset store beased on disconnect state, as it can be set by the lirary, not just user interactions -way to set time for nodes, ntp? - -meshtastic.js -- fix entering device-reconnecting state and not re-connecting despite packets being received \ No newline at end of file diff --git a/types/github.ts b/types/github.ts deleted file mode 100644 index d8f7435e..00000000 --- a/types/github.ts +++ /dev/null @@ -1,39 +0,0 @@ -export interface CommitHistory { - data: Data; -} - -export interface Data { - repository: Repository; -} - -export interface Repository { - ref: Ref; -} - -export interface Ref { - name: string; - target: Target; -} - -export interface Target { - history: History; -} - -export interface History { - edges: Edge[]; -} - -export interface Edge { - node: Node; -} - -export interface Node { - abbreviatedOid: string; - message: string; - author: Author; -} - -export interface Author { - avatarUrl: string; - name: string; -}