6 changed files with 114 additions and 56 deletions
@ -4,7 +4,7 @@ specifiers: |
|||||
'@emeraldpay/hashicon-react': ^0.5.2 |
'@emeraldpay/hashicon-react': ^0.5.2 |
||||
'@floating-ui/react-dom': ^0.4.3 |
'@floating-ui/react-dom': ^0.4.3 |
||||
'@meshtastic/components': ^1.0.23 |
'@meshtastic/components': ^1.0.23 |
||||
'@meshtastic/meshtasticjs': ^0.6.42 |
'@meshtastic/meshtasticjs': ^0.6.43 |
||||
'@reduxjs/toolkit': ^1.7.2 |
'@reduxjs/toolkit': ^1.7.2 |
||||
'@types/mapbox-gl': ^2.6.1 |
'@types/mapbox-gl': ^2.6.1 |
||||
'@types/react': ^17.0.39 |
'@types/react': ^17.0.39 |
||||
@ -62,7 +62,7 @@ dependencies: |
|||||
'@emeraldpay/hashicon-react': 0.5.2 |
'@emeraldpay/hashicon-react': 0.5.2 |
||||
'@floating-ui/react-dom': 0.4.3_b8fdba992ce7d797017dc07106486496 |
'@floating-ui/react-dom': 0.4.3_b8fdba992ce7d797017dc07106486496 |
||||
'@meshtastic/components': 1.0.23_@[email protected] |
'@meshtastic/components': 1.0.23_@[email protected] |
||||
'@meshtastic/meshtasticjs': 0.6.42 |
'@meshtastic/meshtasticjs': 0.6.43 |
||||
'@reduxjs/toolkit': 1.7[email protected][email protected] |
'@reduxjs/toolkit': 1.7[email protected][email protected] |
||||
base64-js: 1.5.1 |
base64-js: 1.5.1 |
||||
framer-motion: 6.2[email protected][email protected] |
framer-motion: 6.2[email protected][email protected] |
||||
@ -1587,8 +1587,8 @@ packages: |
|||||
- '@types/react' |
- '@types/react' |
||||
dev: false |
dev: false |
||||
|
|
||||
/@meshtastic/meshtasticjs/0.6.42: |
/@meshtastic/meshtasticjs/0.6.43: |
||||
resolution: {integrity: sha512-sZLsOZXyrMUIVk4HSRsOAtk50IcWb9qEeIfq4i92khbXQvb52yRMAXrt4BBjc3HgnFK4F5gb1KUdLnCpM9QN+A==} |
resolution: {integrity: sha512-INI9hj3AzjkXzJIp2yq65eV908wTCk6Ih5/5fMknKhwOgx14eC6d5qhlWxjC85kHB6gu8c/2KF3LUCFKHh+1fg==} |
||||
dependencies: |
dependencies: |
||||
'@protobuf-ts/runtime': 2.2.2 |
'@protobuf-ts/runtime': 2.2.2 |
||||
sub-events: 1.8.9 |
sub-events: 1.8.9 |
||||
|
|||||
@ -1,62 +1,115 @@ |
|||||
import React from 'react'; |
import type React from 'react'; |
||||
|
|
||||
|
import { m } from 'framer-motion'; |
||||
|
import { FiArrowRight } from 'react-icons/fi'; |
||||
|
|
||||
import { useAppSelector } from '@app/hooks/useAppSelector'; |
import { useAppSelector } from '@app/hooks/useAppSelector'; |
||||
import { Protobuf } from '@meshtastic/meshtasticjs'; |
import { Protobuf, Types } from '@meshtastic/meshtasticjs'; |
||||
|
|
||||
export const Logs = (): JSX.Element => { |
export const Logs = (): JSX.Element => { |
||||
const logs = useAppSelector((state) => state.meshtastic.logs); |
const logs = useAppSelector((state) => state.meshtastic.logs); |
||||
|
|
||||
const logColor = (level: Protobuf.LogRecord_Level): string => { |
type lookupType = { [key: number]: string }; |
||||
switch (level) { |
|
||||
case Protobuf.LogRecord_Level.UNSET: |
const emitterLookup: lookupType = { |
||||
return 'text-blue-500'; |
[Types.Emitter.sendPacket]: 'text-blue-500', |
||||
case Protobuf.LogRecord_Level.CRITICAL: |
[Types.Emitter.sendText]: 'text-blue-500', |
||||
return 'text-blue-500'; |
[Types.Emitter.sendPacket]: 'text-blue-500', |
||||
case Protobuf.LogRecord_Level.ERROR: |
[Types.Emitter.sendRaw]: 'text-blue-500', |
||||
return 'text-blue-500'; |
[Types.Emitter.setPreferences]: 'text-blue-500', |
||||
case Protobuf.LogRecord_Level.WARNING: |
[Types.Emitter.confirmSetPreferences]: 'text-blue-500', |
||||
return 'text-blue-500'; |
[Types.Emitter.setOwner]: 'text-blue-500', |
||||
case Protobuf.LogRecord_Level.INFO: |
[Types.Emitter.setChannel]: 'text-blue-500', |
||||
return 'text-blue-500'; |
[Types.Emitter.confirmSetChannel]: 'text-blue-500', |
||||
case Protobuf.LogRecord_Level.DEBUG: |
[Types.Emitter.deleteChannel]: 'text-blue-500', |
||||
return 'text-blue-500'; |
[Types.Emitter.getChannel]: 'text-blue-500', |
||||
case Protobuf.LogRecord_Level.TRACE: |
[Types.Emitter.getAllChannels]: 'text-blue-500', |
||||
return 'text-blue-500'; |
[Types.Emitter.getPreferences]: 'text-blue-500', |
||||
} |
[Types.Emitter.getOwner]: 'text-blue-500', |
||||
|
[Types.Emitter.configure]: 'text-blue-500', |
||||
|
[Types.Emitter.handleFromRadio]: 'text-blue-500', |
||||
|
[Types.Emitter.handleMeshPacket]: 'text-blue-500', |
||||
|
[Types.Emitter.connect]: 'text-blue-500', |
||||
|
[Types.Emitter.ping]: 'text-blue-500', |
||||
|
[Types.Emitter.readFromRadio]: 'text-blue-500', |
||||
|
[Types.Emitter.writeToRadio]: 'text-blue-500', |
||||
|
[Types.Emitter.setDebugMode]: 'text-blue-500', |
||||
}; |
}; |
||||
|
|
||||
const stringToColour = (str: string) => { |
const levelLookup: lookupType = { |
||||
let hash = 0; |
[Protobuf.LogRecord_Level.UNSET]: 'text-green-500', |
||||
for (let i = 0; i < str.length; i++) { |
[Protobuf.LogRecord_Level.CRITICAL]: 'text-purple-500', |
||||
hash = str.charCodeAt(i) + ((hash << 5) - hash); |
[Protobuf.LogRecord_Level.ERROR]: 'text-red-500', |
||||
} |
[Protobuf.LogRecord_Level.WARNING]: 'text-orange-500', |
||||
let colour = '#'; |
[Protobuf.LogRecord_Level.INFO]: 'text-blue-500', |
||||
for (let i = 0; i < 3; i++) { |
[Protobuf.LogRecord_Level.DEBUG]: 'text-neutral-500', |
||||
const value = (hash >> (i * 8)) & 0xff; |
[Protobuf.LogRecord_Level.TRACE]: 'text-slate-500', |
||||
colour += ('00' + value.toString(16)).substr(-2); |
|
||||
} |
|
||||
return colour; |
|
||||
}; |
}; |
||||
|
|
||||
return ( |
return ( |
||||
<div className="flex h-full w-full select-none flex-col gap-4 p-4"> |
<div className="flex h-full p-4 "> |
||||
<div className="flex w-full select-none flex-col gap-2 overflow-y-auto rounded-md p-4 shadow-md dark:bg-primaryDark"> |
<table className="table-cell h-full w-full select-none rounded-md dark:bg-primaryDark"> |
||||
{logs.map((log, index) => ( |
{/* \/ flex flex-col gap-2 */} |
||||
<div key={index} className="flex gap-2"> |
<tbody |
||||
<div className="text-sm font-light dark:text-gray-400"> |
className=" |
||||
{log.date.toISOString()} |
block h-full flex-col overflow-y-auto py-4 px-2 font-mono text-xs dark:text-gray-400" |
||||
</div> |
> |
||||
<div>[{log.emitter}]</div> |
{logs.map((log, index) => ( |
||||
<div className={`text-sm font-medium ${logColor(log.level)}`}> |
<tr key={index} className="group hover:bg-secondaryDark"> |
||||
[{Protobuf.LogRecord_Level[log.level]}] |
<m.td |
||||
</div> |
className="w-6 cursor-pointer" |
||||
<div style={{ color: stringToColour(log.emitter) }}> |
whileHover={{ scale: 1.01 }} |
||||
{stringToColour(log.emitter)} |
whileTap={{ scale: 0.99 }} |
||||
</div> |
> |
||||
<div>{log.message}</div> |
<div className="m-auto pl-2 dark:text-primaryDark dark:group-hover:text-gray-400"> |
||||
</div> |
<FiArrowRight /> |
||||
))} |
</div> |
||||
</div> |
</m.td> |
||||
|
<Wrapper> |
||||
|
{log.date |
||||
|
.toLocaleString(undefined, { |
||||
|
year: 'numeric', |
||||
|
month: '2-digit', |
||||
|
day: '2-digit', |
||||
|
|
||||
|
hour: '2-digit', |
||||
|
minute: '2-digit', |
||||
|
second: '2-digit', |
||||
|
}) |
||||
|
.replaceAll('/', '-') |
||||
|
.replace(',', '')} |
||||
|
</Wrapper> |
||||
|
<Wrapper> |
||||
|
<div className={emitterLookup[log.emitter]}> |
||||
|
[{Types.EmitterScope[log.scope]}.{Types.Emitter[log.emitter]}] |
||||
|
</div> |
||||
|
</Wrapper> |
||||
|
<Wrapper className={levelLookup[log.level]}> |
||||
|
[{Protobuf.LogRecord_Level[log.level]}]{/* </div> */} |
||||
|
</Wrapper> |
||||
|
<td className="truncate pl-1">{log.message}</td> |
||||
|
</tr> |
||||
|
))} |
||||
|
</tbody> |
||||
|
</table> |
||||
</div> |
</div> |
||||
); |
); |
||||
}; |
}; |
||||
|
|
||||
|
const Wrapper = ({ |
||||
|
className, |
||||
|
children, |
||||
|
}: { |
||||
|
className?: string; |
||||
|
children: React.ReactNode; |
||||
|
}): JSX.Element => ( |
||||
|
<td className={className}> |
||||
|
<m.div |
||||
|
className="-my-0.5 flex max-w-min cursor-pointer truncate rounded-sm px-0.5 hover:bg-gray-700" |
||||
|
whileHover={{ scale: 1.01 }} |
||||
|
whileTap={{ scale: 0.99 }} |
||||
|
> |
||||
|
{children} |
||||
|
</m.div> |
||||
|
</td> |
||||
|
); |
||||
|
|||||
Loading…
Reference in new issue