Get suspense working and cleanup TL system
This commit is contained in:
+4
-5
@@ -13,9 +13,8 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@headlessui/react": "^1.2.0",
|
"@headlessui/react": "^1.2.0",
|
||||||
"@heroicons/react": "^1.0.1",
|
"@heroicons/react": "^1.0.1",
|
||||||
"@meshtastic/meshtasticjs": "^0.6.12",
|
"@meshtastic/meshtasticjs": "^0.6.13",
|
||||||
"@react-rxjs/core": "^0.8.0",
|
"boring-avatars": "^1.5.5",
|
||||||
"boring-avatars": "^1.5.4",
|
|
||||||
"observable-hooks": "^4.0.3",
|
"observable-hooks": "^4.0.3",
|
||||||
"react": "^0.0.0-experimental-d75105fa9",
|
"react": "^0.0.0-experimental-d75105fa9",
|
||||||
"react-dom": "^0.0.0-experimental-d75105fa9",
|
"react-dom": "^0.0.0-experimental-d75105fa9",
|
||||||
@@ -34,8 +33,8 @@
|
|||||||
"@types/react": "^17.0.8",
|
"@types/react": "^17.0.8",
|
||||||
"@types/react-dom": "^17.0.5",
|
"@types/react-dom": "^17.0.5",
|
||||||
"@types/snowpack-env": "^2.3.2",
|
"@types/snowpack-env": "^2.3.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^4.25.0",
|
"@typescript-eslint/eslint-plugin": "^4.26.0",
|
||||||
"@typescript-eslint/parser": "^4.25.0",
|
"@typescript-eslint/parser": "^4.26.0",
|
||||||
"autoprefixer": "^10.2.6",
|
"autoprefixer": "^10.2.6",
|
||||||
"eslint": "^7.27.0",
|
"eslint": "^7.27.0",
|
||||||
"eslint-config-prettier": "^8.3.0",
|
"eslint-config-prettier": "^8.3.0",
|
||||||
|
|||||||
+14
-66
@@ -1,8 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { ObservableResource } from 'observable-hooks';
|
|
||||||
import { Subject } from 'rxjs';
|
|
||||||
|
|
||||||
import type {
|
import type {
|
||||||
IBLEConnection,
|
IBLEConnection,
|
||||||
ISerialConnection,
|
ISerialConnection,
|
||||||
@@ -17,43 +14,12 @@ import {
|
|||||||
|
|
||||||
import Header from './components/Header';
|
import Header from './components/Header';
|
||||||
import Main from './Main';
|
import Main from './Main';
|
||||||
|
import { channelSubject$, nodeSubject$, preferencesSubject$ } from './streams';
|
||||||
import Translations_English from './translations/en';
|
import Translations_English from './translations/en';
|
||||||
import Translations_Japanese from './translations/jp';
|
import Translations_Japanese from './translations/jp';
|
||||||
import Translations_Portuguese from './translations/pt';
|
import Translations_Portuguese from './translations/pt';
|
||||||
|
import type { languageTemplate } from './translations/TranslationContext';
|
||||||
export enum LanguageEnum {
|
import { LanguageEnum } from './translations/TranslationContext';
|
||||||
ENGLISH,
|
|
||||||
JAPANESE,
|
|
||||||
PORTUGUESE,
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface languageTemplate {
|
|
||||||
no_messages_message: string;
|
|
||||||
ui_settings_title: string;
|
|
||||||
nodes_title: string;
|
|
||||||
color_scheme_title: string;
|
|
||||||
language_title: string;
|
|
||||||
device_settings_title: string;
|
|
||||||
device_channels_title: string;
|
|
||||||
device_region_title: string;
|
|
||||||
device_wifi_ssid: string;
|
|
||||||
device_wifi_psk: string;
|
|
||||||
save_changes_button: string;
|
|
||||||
no_nodes_message: string;
|
|
||||||
no_message_placeholder: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
// const adminPacketResource = useSuspense(props.connection.onAdminPacketEvent);
|
|
||||||
// const tmp$ = new Subject<Types.AdminPacket>().pipe(
|
|
||||||
// filter(
|
|
||||||
// (adminPacket) =>
|
|
||||||
// adminPacket.data.variant.oneofKind === 'getRadioResponse',
|
|
||||||
// ),
|
|
||||||
// );
|
|
||||||
// const tmp$ = props.connection.onAdminPacketEvent;
|
|
||||||
const tmpSubject = new Subject<Protobuf.RadioConfig_UserPreferences>();
|
|
||||||
|
|
||||||
export const adminPacketResource = new ObservableResource(tmpSubject);
|
|
||||||
|
|
||||||
const App = (): JSX.Element => {
|
const App = (): JSX.Element => {
|
||||||
const [deviceStatus, setDeviceStatus] =
|
const [deviceStatus, setDeviceStatus] =
|
||||||
@@ -63,7 +29,7 @@ const App = (): JSX.Element => {
|
|||||||
const [myNodeInfo, setMyNodeInfo] = React.useState<Protobuf.MyNodeInfo>(
|
const [myNodeInfo, setMyNodeInfo] = React.useState<Protobuf.MyNodeInfo>(
|
||||||
Protobuf.MyNodeInfo.create(),
|
Protobuf.MyNodeInfo.create(),
|
||||||
);
|
);
|
||||||
const [channels, setChannels] = React.useState([] as Protobuf.Channel[]);
|
// const [channels, setChannels] = React.useState([] as Protobuf.Channel[]);
|
||||||
const [nodes, setNodes] = React.useState<Types.NodeInfoPacket[]>([]);
|
const [nodes, setNodes] = React.useState<Types.NodeInfoPacket[]>([]);
|
||||||
const [connection, setConnection] = React.useState<
|
const [connection, setConnection] = React.useState<
|
||||||
ISerialConnection | IHTTPConnection | IBLEConnection
|
ISerialConnection | IHTTPConnection | IBLEConnection
|
||||||
@@ -98,9 +64,9 @@ const App = (): JSX.Element => {
|
|||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
const client = new Client();
|
const client = new Client();
|
||||||
const connection = client.createHTTPConnection();
|
const tmpConnection = client.createHTTPConnection();
|
||||||
|
|
||||||
connection.connect({
|
tmpConnection.connect({
|
||||||
address:
|
address:
|
||||||
import.meta.env.NODE_ENV === 'production'
|
import.meta.env.NODE_ENV === 'production'
|
||||||
? window.location.hostname
|
? window.location.hostname
|
||||||
@@ -109,13 +75,11 @@ const App = (): JSX.Element => {
|
|||||||
tls: false,
|
tls: false,
|
||||||
fetchInterval: 2000,
|
fetchInterval: 2000,
|
||||||
});
|
});
|
||||||
setConnection(connection);
|
setConnection(tmpConnection);
|
||||||
SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE;
|
SettingsManager.debugMode = Protobuf.LogRecord_Level.TRACE;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
console.log('UPDATING');
|
|
||||||
|
|
||||||
const deviceStatusEvent = connection.onDeviceStatusEvent.subscribe(
|
const deviceStatusEvent = connection.onDeviceStatusEvent.subscribe(
|
||||||
(status) => {
|
(status) => {
|
||||||
setDeviceStatus(status);
|
setDeviceStatus(status);
|
||||||
@@ -128,34 +92,21 @@ const App = (): JSX.Element => {
|
|||||||
connection.onMyNodeInfoEvent.subscribe(setMyNodeInfo);
|
connection.onMyNodeInfoEvent.subscribe(setMyNodeInfo);
|
||||||
|
|
||||||
const nodeInfoPacketEvent = connection.onNodeInfoPacketEvent.subscribe(
|
const nodeInfoPacketEvent = connection.onNodeInfoPacketEvent.subscribe(
|
||||||
(node) => {
|
(node) => nodeSubject$.next(node),
|
||||||
if (
|
|
||||||
nodes.findIndex(
|
|
||||||
(currentNode) => currentNode.data.num === node.data.num,
|
|
||||||
) >= 0
|
|
||||||
) {
|
|
||||||
setNodes(
|
|
||||||
nodes.map((currentNode) =>
|
|
||||||
currentNode.data.num === node.data.num ? node : currentNode,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
setNodes((nodes) => [...nodes, node]);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
const adminPacketEvent = connection.onAdminPacketEvent.subscribe(
|
const adminPacketEvent = connection.onAdminPacketEvent.subscribe(
|
||||||
(adminMessage) => {
|
(adminMessage) => {
|
||||||
switch (adminMessage.data.variant.oneofKind) {
|
switch (adminMessage.data.variant.oneofKind) {
|
||||||
case 'getChannelResponse':
|
case 'getChannelResponse':
|
||||||
setChannels((channels) => [
|
channelSubject$.next(adminMessage.data.variant.getChannelResponse);
|
||||||
...channels,
|
|
||||||
adminMessage.data.variant.getChannelResponse,
|
|
||||||
]);
|
|
||||||
break;
|
break;
|
||||||
case 'getRadioResponse':
|
case 'getRadioResponse':
|
||||||
tmpSubject.next(adminMessage.data.variant.getRadioResponse);
|
if (adminMessage.data.variant.getRadioResponse.preferences) {
|
||||||
|
preferencesSubject$.next(
|
||||||
|
adminMessage.data.variant.getRadioResponse.preferences,
|
||||||
|
);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
@@ -190,11 +141,8 @@ const App = (): JSX.Element => {
|
|||||||
isReady={isReady}
|
isReady={isReady}
|
||||||
myNodeInfo={myNodeInfo}
|
myNodeInfo={myNodeInfo}
|
||||||
connection={connection}
|
connection={connection}
|
||||||
nodes={nodes}
|
|
||||||
channels={channels}
|
|
||||||
language={language}
|
language={language}
|
||||||
setLanguage={setLanguage}
|
setLanguage={setLanguage}
|
||||||
translations={translations}
|
|
||||||
darkmode={darkmode}
|
darkmode={darkmode}
|
||||||
setDarkmode={setDarkmode}
|
setDarkmode={setDarkmode}
|
||||||
/>
|
/>
|
||||||
|
|||||||
+4
-10
@@ -8,25 +8,24 @@ import type {
|
|||||||
Types,
|
Types,
|
||||||
} from '@meshtastic/meshtasticjs';
|
} from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import type { LanguageEnum, languageTemplate } from './App';
|
|
||||||
import ChatMessage from './components/ChatMessage';
|
import ChatMessage from './components/ChatMessage';
|
||||||
import MessageBox from './components/MessageBox';
|
import MessageBox from './components/MessageBox';
|
||||||
import Sidebar from './components/Sidebar';
|
import Sidebar from './components/Sidebar';
|
||||||
|
import type { LanguageEnum } from './translations/TranslationContext';
|
||||||
|
import { TranslationContext } from './translations/TranslationContext';
|
||||||
|
|
||||||
interface MainProps {
|
interface MainProps {
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
||||||
myNodeInfo: Protobuf.MyNodeInfo;
|
myNodeInfo: Protobuf.MyNodeInfo;
|
||||||
nodes: Types.NodeInfoPacket[];
|
|
||||||
channels: Protobuf.Channel[];
|
|
||||||
isReady: boolean;
|
isReady: boolean;
|
||||||
language: LanguageEnum;
|
language: LanguageEnum;
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
||||||
translations: languageTemplate;
|
|
||||||
darkmode: boolean;
|
darkmode: boolean;
|
||||||
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Main = (props: MainProps): JSX.Element => {
|
const Main = (props: MainProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
const [messages, setMessages] = React.useState<
|
const [messages, setMessages] = React.useState<
|
||||||
{ message: Types.TextPacket; ack: boolean }[]
|
{ message: Types.TextPacket; ack: boolean }[]
|
||||||
>([]);
|
>([]);
|
||||||
@@ -72,7 +71,6 @@ const Main = (props: MainProps): JSX.Element => {
|
|||||||
{messages.length ? (
|
{messages.length ? (
|
||||||
messages.map((message, Main) => (
|
messages.map((message, Main) => (
|
||||||
<ChatMessage
|
<ChatMessage
|
||||||
nodes={props.nodes}
|
|
||||||
key={Main}
|
key={Main}
|
||||||
message={message}
|
message={message}
|
||||||
myId={props.myNodeInfo.myNodeNum}
|
myId={props.myNodeInfo.myNodeNum}
|
||||||
@@ -80,7 +78,7 @@ const Main = (props: MainProps): JSX.Element => {
|
|||||||
))
|
))
|
||||||
) : (
|
) : (
|
||||||
<div className="m-auto text-2xl text-gray-500">
|
<div className="m-auto text-2xl text-gray-500">
|
||||||
{props.translations.no_messages_message}
|
{translations.no_messages_message}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -89,17 +87,13 @@ const Main = (props: MainProps): JSX.Element => {
|
|||||||
isReady={props.isReady}
|
isReady={props.isReady}
|
||||||
sidebarOpen={sidebarOpen}
|
sidebarOpen={sidebarOpen}
|
||||||
setSidebarOpen={setSidebarOpen}
|
setSidebarOpen={setSidebarOpen}
|
||||||
translations={props.translations}
|
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<Sidebar
|
<Sidebar
|
||||||
isReady={props.isReady}
|
isReady={props.isReady}
|
||||||
nodes={props.nodes}
|
|
||||||
channels={props.channels}
|
|
||||||
connection={props.connection}
|
connection={props.connection}
|
||||||
language={props.language}
|
language={props.language}
|
||||||
setLanguage={props.setLanguage}
|
setLanguage={props.setLanguage}
|
||||||
translations={props.translations}
|
|
||||||
myId={props.myNodeInfo.myNodeNum}
|
myId={props.myNodeInfo.myNodeNum}
|
||||||
sidebarOpen={sidebarOpen}
|
sidebarOpen={sidebarOpen}
|
||||||
darkmode={props.darkmode}
|
darkmode={props.darkmode}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
|
||||||
import Avatar from 'boring-avatars';
|
import Avatar from 'boring-avatars';
|
||||||
|
import { useObservableSuspense } from 'observable-hooks';
|
||||||
|
|
||||||
import {
|
import {
|
||||||
CheckCircleIcon,
|
CheckCircleIcon,
|
||||||
@@ -8,22 +9,42 @@ import {
|
|||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
import type { Types } from '@meshtastic/meshtasticjs';
|
import type { Types } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
|
import { nodeResource } from '../streams';
|
||||||
|
|
||||||
interface ChatMessageProps {
|
interface ChatMessageProps {
|
||||||
message: { message: Types.TextPacket; ack: boolean };
|
message: { message: Types.TextPacket; ack: boolean };
|
||||||
myId: number;
|
myId: number;
|
||||||
nodes: Types.NodeInfoPacket[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatMessage = (props: ChatMessageProps): JSX.Element => {
|
const ChatMessage = (props: ChatMessageProps): JSX.Element => {
|
||||||
|
const nodeSource = useObservableSuspense(nodeResource);
|
||||||
|
|
||||||
|
const [nodes, setNodes] = React.useState<Types.NodeInfoPacket[]>([]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (
|
||||||
|
nodes.findIndex(
|
||||||
|
(currentNode) => currentNode.data.num === nodeSource.data.num,
|
||||||
|
) >= 0
|
||||||
|
) {
|
||||||
|
setNodes(
|
||||||
|
nodes.map((currentNode) =>
|
||||||
|
currentNode.data.num === nodeSource.data.num
|
||||||
|
? nodeSource
|
||||||
|
: currentNode,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setNodes((nodes) => [...nodes, nodeSource]);
|
||||||
|
}
|
||||||
|
}, [nodeSource, nodes]);
|
||||||
const [node, setNode] = useState<Types.NodeInfoPacket>();
|
const [node, setNode] = useState<Types.NodeInfoPacket>();
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setNode(
|
setNode(
|
||||||
props.nodes.find(
|
nodes.find((node) => node.data.num === props.message.message.packet.from),
|
||||||
(node) => node.data.num === props.message.message.packet.from,
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}, [props.nodes, props.message]);
|
}, [nodes, props.message]);
|
||||||
return (
|
return (
|
||||||
<div className="flex items-end">
|
<div className="flex items-end">
|
||||||
<Avatar
|
<Avatar
|
||||||
|
|||||||
@@ -7,10 +7,9 @@ import type {
|
|||||||
ISerialConnection,
|
ISerialConnection,
|
||||||
} from '@meshtastic/meshtasticjs';
|
} from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import type { languageTemplate } from '../App';
|
import { TranslationContext } from '../translations/TranslationContext';
|
||||||
|
|
||||||
export interface MessageBoxProps {
|
export interface MessageBoxProps {
|
||||||
translations: languageTemplate;
|
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
setSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
setSidebarOpen: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
||||||
@@ -18,6 +17,7 @@ export interface MessageBoxProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const MessageBox = (props: MessageBoxProps): JSX.Element => {
|
const MessageBox = (props: MessageBoxProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
const [currentMessage, setCurrentMessage] = React.useState('');
|
const [currentMessage, setCurrentMessage] = React.useState('');
|
||||||
const sendMessage = () => {
|
const sendMessage = () => {
|
||||||
if (props.isReady) {
|
if (props.isReady) {
|
||||||
@@ -45,7 +45,7 @@ const MessageBox = (props: MessageBoxProps): JSX.Element => {
|
|||||||
{props.isReady}
|
{props.isReady}
|
||||||
<input
|
<input
|
||||||
type="text"
|
type="text"
|
||||||
placeholder={`${props.translations.no_message_placeholder}...`}
|
placeholder={`${translations.no_message_placeholder}...`}
|
||||||
disabled={!props.isReady}
|
disabled={!props.isReady}
|
||||||
value={currentMessage}
|
value={currentMessage}
|
||||||
onChange={(e) => {
|
onChange={(e) => {
|
||||||
|
|||||||
@@ -4,11 +4,9 @@ import type {
|
|||||||
IBLEConnection,
|
IBLEConnection,
|
||||||
IHTTPConnection,
|
IHTTPConnection,
|
||||||
ISerialConnection,
|
ISerialConnection,
|
||||||
Protobuf,
|
|
||||||
Types,
|
|
||||||
} from '@meshtastic/meshtasticjs';
|
} from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import type { LanguageEnum, languageTemplate } from '../App';
|
import type { LanguageEnum } from '../translations/TranslationContext';
|
||||||
import Channels from './Sidebar/Channels/Index';
|
import Channels from './Sidebar/Channels/Index';
|
||||||
import Device from './Sidebar/Device/Index';
|
import Device from './Sidebar/Device/Index';
|
||||||
import Nodes from './Sidebar/Nodes/Index';
|
import Nodes from './Sidebar/Nodes/Index';
|
||||||
@@ -16,12 +14,9 @@ import UI from './Sidebar/UI/Index';
|
|||||||
|
|
||||||
interface SidebarProps {
|
interface SidebarProps {
|
||||||
isReady: boolean;
|
isReady: boolean;
|
||||||
nodes: Types.NodeInfoPacket[];
|
|
||||||
channels: Protobuf.Channel[];
|
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
||||||
language: LanguageEnum;
|
language: LanguageEnum;
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
||||||
translations: languageTemplate;
|
|
||||||
myId: number;
|
myId: number;
|
||||||
sidebarOpen: boolean;
|
sidebarOpen: boolean;
|
||||||
darkmode: boolean;
|
darkmode: boolean;
|
||||||
@@ -35,27 +30,13 @@ const Sidebar = (props: SidebarProps): JSX.Element => {
|
|||||||
props.sidebarOpen ? 'flex' : 'hidden md:flex'
|
props.sidebarOpen ? 'flex' : 'hidden md:flex'
|
||||||
} flex-col rounded-md md:ml-0 shadow-md border w-full max-w-sm`}
|
} flex-col rounded-md md:ml-0 shadow-md border w-full max-w-sm`}
|
||||||
>
|
>
|
||||||
<Nodes
|
<Nodes myId={props.myId} />
|
||||||
isReady={props.isReady}
|
<Device isReady={props.isReady} connection={props.connection} />
|
||||||
nodes={props.nodes}
|
<Channels />
|
||||||
translations={props.translations}
|
|
||||||
myId={props.myId}
|
|
||||||
/>
|
|
||||||
<Device
|
|
||||||
isReady={props.isReady}
|
|
||||||
connection={props.connection}
|
|
||||||
translations={props.translations}
|
|
||||||
/>
|
|
||||||
<Channels
|
|
||||||
isReady={props.isReady}
|
|
||||||
channels={props.channels}
|
|
||||||
translations={props.translations}
|
|
||||||
/>
|
|
||||||
<div className="flex-grow border-b"></div>
|
<div className="flex-grow border-b"></div>
|
||||||
<UI
|
<UI
|
||||||
language={props.language}
|
language={props.language}
|
||||||
setLanguage={props.setLanguage}
|
setLanguage={props.setLanguage}
|
||||||
translations={props.translations}
|
|
||||||
darkmode={props.darkmode}
|
darkmode={props.darkmode}
|
||||||
setDarkmode={props.setDarkmode}
|
setDarkmode={props.setDarkmode}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -0,0 +1,43 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useObservableSuspense } from 'observable-hooks';
|
||||||
|
|
||||||
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
|
import { channelResource } from '../../../streams';
|
||||||
|
import Channel from './Channel';
|
||||||
|
|
||||||
|
const ChannelList = (): JSX.Element => {
|
||||||
|
const channelSource = useObservableSuspense(channelResource);
|
||||||
|
|
||||||
|
const [channels, setChannels] = React.useState<Protobuf.Channel[]>([]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (
|
||||||
|
channels.findIndex(
|
||||||
|
(currentChannel) => currentChannel.index === channelSource.index,
|
||||||
|
) >= 0
|
||||||
|
) {
|
||||||
|
setChannels(
|
||||||
|
channels.map((currentChannel) =>
|
||||||
|
currentChannel.index === channelSource.index
|
||||||
|
? channelSource
|
||||||
|
: currentChannel,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setChannels((channels) => [...channels, channelSource]);
|
||||||
|
}
|
||||||
|
}, [channelSource, channels]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{channels.map((channel, index) => {
|
||||||
|
if (channel.role !== Protobuf.Channel_Role.DISABLED)
|
||||||
|
return <Channel key={index} channel={channel} />;
|
||||||
|
})}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ChannelList;
|
||||||
@@ -6,18 +6,12 @@ import {
|
|||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
HashtagIcon,
|
HashtagIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
|
||||||
|
|
||||||
import type { languageTemplate } from '../../../App';
|
import { TranslationContext } from '../../../translations/TranslationContext';
|
||||||
import Channel from './Channel';
|
import ChannelList from './ChannelList';
|
||||||
|
|
||||||
export interface ChannelsProps {
|
const Channels = (): JSX.Element => {
|
||||||
isReady: boolean;
|
const { translations } = React.useContext(TranslationContext);
|
||||||
channels: Protobuf.Channel[];
|
|
||||||
translations: languageTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
const Channels = (props: ChannelsProps): JSX.Element => {
|
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -30,16 +24,19 @@ const Channels = (props: ChannelsProps): JSX.Element => {
|
|||||||
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
||||||
)}
|
)}
|
||||||
<HashtagIcon className="my-auto text-gray-600 mr-2 2-5 h-5" />
|
<HashtagIcon className="my-auto text-gray-600 mr-2 2-5 h-5" />
|
||||||
{props.translations.device_channels_title}
|
{translations.device_channels_title}
|
||||||
</div>
|
</div>
|
||||||
</Disclosure.Button>
|
</Disclosure.Button>
|
||||||
<Disclosure.Panel>
|
<Disclosure.Panel>
|
||||||
<>
|
<React.Suspense
|
||||||
{props.channels.map((channel, index) => {
|
fallback={
|
||||||
if (channel.role !== Protobuf.Channel_Role.DISABLED)
|
<div className="flex border-b border-gray-300">
|
||||||
return <Channel key={index} channel={channel} />;
|
<div className="m-auto p-3 text-gray-500">Loading...</div>
|
||||||
})}
|
</div>
|
||||||
</>
|
}
|
||||||
|
>
|
||||||
|
<ChannelList />
|
||||||
|
</React.Suspense>
|
||||||
</Disclosure.Panel>
|
</Disclosure.Panel>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { Suspense } from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
import { Disclosure } from '@headlessui/react';
|
import { Disclosure } from '@headlessui/react';
|
||||||
import {
|
import {
|
||||||
@@ -12,16 +12,16 @@ import type {
|
|||||||
ISerialConnection,
|
ISerialConnection,
|
||||||
} from '@meshtastic/meshtasticjs';
|
} from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import type { languageTemplate } from '../../../App';
|
import { TranslationContext } from '../../../translations/TranslationContext';
|
||||||
import Settings from './Settings';
|
import Settings from './Settings';
|
||||||
|
|
||||||
interface DeviceProps {
|
interface DeviceProps {
|
||||||
isReady: boolean;
|
isReady: boolean;
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
||||||
translations: languageTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Device = (props: DeviceProps): JSX.Element => {
|
const Device = (props: DeviceProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -34,18 +34,23 @@ const Device = (props: DeviceProps): JSX.Element => {
|
|||||||
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
||||||
)}
|
)}
|
||||||
<AdjustmentsIcon className="text-gray-600 my-auto mr-2 w-5 h-5" />
|
<AdjustmentsIcon className="text-gray-600 my-auto mr-2 w-5 h-5" />
|
||||||
{props.translations.device_settings_title}
|
{translations.device_settings_title}
|
||||||
</div>
|
</div>
|
||||||
</Disclosure.Button>
|
</Disclosure.Button>
|
||||||
<Disclosure.Panel>
|
<Disclosure.Panel>
|
||||||
<>
|
<>
|
||||||
<Suspense fallback={<div>loading</div>}>
|
<React.Suspense
|
||||||
|
fallback={
|
||||||
|
<div className="flex border-b border-gray-300">
|
||||||
|
<div className="m-auto p-3 text-gray-500">Loading...</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
>
|
||||||
<Settings
|
<Settings
|
||||||
connection={props.connection}
|
connection={props.connection}
|
||||||
isReady={props.isReady}
|
isReady={props.isReady}
|
||||||
translations={props.translations}
|
|
||||||
/>
|
/>
|
||||||
</Suspense>
|
</React.Suspense>
|
||||||
</>
|
</>
|
||||||
</Disclosure.Panel>
|
</Disclosure.Panel>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -1,29 +1,94 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useObservableSuspense } from 'observable-hooks';
|
||||||
|
import { useForm } from 'react-hook-form';
|
||||||
|
import JSONPretty from 'react-json-pretty';
|
||||||
|
|
||||||
|
import { SaveIcon } from '@heroicons/react/outline';
|
||||||
import type {
|
import type {
|
||||||
IBLEConnection,
|
IBLEConnection,
|
||||||
IHTTPConnection,
|
IHTTPConnection,
|
||||||
ISerialConnection,
|
ISerialConnection,
|
||||||
} from '@meshtastic/meshtasticjs';
|
} from '@meshtastic/meshtasticjs';
|
||||||
|
import { Protobuf } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
import type { languageTemplate } from '../../../../src/App';
|
import { preferencesResource } from '../../../streams';
|
||||||
import SettingsForm from './SettingsForm';
|
import { TranslationContext } from '../../../translations/TranslationContext';
|
||||||
|
|
||||||
export interface SettingsProps {
|
export interface SettingsProps {
|
||||||
isReady: boolean;
|
isReady: boolean;
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
||||||
translations: languageTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Settings = (props: SettingsProps): JSX.Element => {
|
const Settings = (props: SettingsProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
|
const preferences = useObservableSuspense(preferencesResource);
|
||||||
|
|
||||||
|
const { register, handleSubmit } =
|
||||||
|
useForm<Protobuf.RadioConfig_UserPreferences>({
|
||||||
|
defaultValues: preferences,
|
||||||
|
});
|
||||||
|
|
||||||
|
const onSubmit = handleSubmit((data) => console.log(data));
|
||||||
return (
|
return (
|
||||||
<React.Suspense fallback={<div>Loading....</div>}>
|
<form onSubmit={onSubmit}>
|
||||||
<SettingsForm
|
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
|
||||||
connection={props.connection}
|
<div className="my-auto">{translations.device_region_title}</div>
|
||||||
isReady={props.isReady}
|
<div className="flex shadow-md rounded-md ml-2">
|
||||||
translations={props.translations}
|
<select value={preferences?.region ?? Protobuf.RegionCode.Unset}>
|
||||||
/>
|
<option value={Protobuf.RegionCode.ANZ}>
|
||||||
</React.Suspense>
|
{Protobuf.RegionCode[Protobuf.RegionCode.ANZ]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.CN}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.CN]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.EU433}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.EU433]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.EU865}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.EU865]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.JP}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.JP]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.KR}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.KR]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.TW}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.TW]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.US}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.US]}
|
||||||
|
</option>
|
||||||
|
<option value={Protobuf.RegionCode.Unset}>
|
||||||
|
{Protobuf.RegionCode[Protobuf.RegionCode.Unset]}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
|
||||||
|
<div className="my-auto">{translations.device_wifi_ssid}</div>
|
||||||
|
<div className="flex shadow-md rounded-md ml-2">
|
||||||
|
<input {...register('wifiSsid', {})} type="text" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
|
||||||
|
<div className="my-auto">{translations.device_wifi_psk}</div>
|
||||||
|
<div className="flex shadow-md rounded-md ml-2">
|
||||||
|
<input {...register('wifiPassword', {})} type="password" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="flex bg-gray-100 group p-1 cursor-pointer hover:bg-gray-200 border-b">
|
||||||
|
<button
|
||||||
|
type="submit"
|
||||||
|
className="flex m-auto font-medium group-hover:text-gray-700"
|
||||||
|
>
|
||||||
|
<SaveIcon className="m-auto mr-2 group-hover:text-gray-700 w-5 h-5" />
|
||||||
|
{translations.save_changes_button}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<JSONPretty data={preferences} />
|
||||||
|
</form>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,95 +0,0 @@
|
|||||||
import React from 'react';
|
|
||||||
|
|
||||||
import { useObservableSuspense } from 'observable-hooks';
|
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
import JSONPretty from 'react-json-pretty';
|
|
||||||
|
|
||||||
import { SaveIcon } from '@heroicons/react/outline';
|
|
||||||
import type {
|
|
||||||
IBLEConnection,
|
|
||||||
IHTTPConnection,
|
|
||||||
ISerialConnection,
|
|
||||||
} from '@meshtastic/meshtasticjs';
|
|
||||||
import { Protobuf } from '@meshtastic/meshtasticjs';
|
|
||||||
|
|
||||||
import type { languageTemplate } from '../../../../src/App';
|
|
||||||
import { adminPacketResource } from '../../../../src/App';
|
|
||||||
|
|
||||||
export interface SettingsFormProps {
|
|
||||||
isReady: boolean;
|
|
||||||
connection: ISerialConnection | IHTTPConnection | IBLEConnection;
|
|
||||||
translations: languageTemplate;
|
|
||||||
}
|
|
||||||
|
|
||||||
const SettingsForm = (props: SettingsFormProps): JSX.Element => {
|
|
||||||
const preferences = useObservableSuspense(adminPacketResource);
|
|
||||||
|
|
||||||
const { register, handleSubmit } =
|
|
||||||
useForm<Protobuf.RadioConfig_UserPreferences>({
|
|
||||||
defaultValues: preferences,
|
|
||||||
});
|
|
||||||
|
|
||||||
const onSubmit = handleSubmit((data) => console.log(data));
|
|
||||||
return (
|
|
||||||
<form onSubmit={onSubmit}>
|
|
||||||
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
|
|
||||||
<div className="my-auto">{props.translations.device_region_title}</div>
|
|
||||||
<div className="flex shadow-md rounded-md ml-2">
|
|
||||||
<select value={preferences?.region ?? Protobuf.RegionCode.Unset}>
|
|
||||||
<option value={Protobuf.RegionCode.ANZ}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.ANZ]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.CN}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.CN]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.EU433}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.EU433]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.EU865}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.EU865]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.JP}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.JP]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.KR}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.KR]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.TW}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.TW]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.US}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.US]}
|
|
||||||
</option>
|
|
||||||
<option value={Protobuf.RegionCode.Unset}>
|
|
||||||
{Protobuf.RegionCode[Protobuf.RegionCode.Unset]}
|
|
||||||
</option>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
|
|
||||||
<div className="my-auto">{props.translations.device_wifi_ssid}</div>
|
|
||||||
<div className="flex shadow-md rounded-md ml-2">
|
|
||||||
<input {...register('wifiSsid', {})} type="text" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex bg-gray-50 whitespace-nowrap p-3 justify-between border-b">
|
|
||||||
<div className="my-auto">{props.translations.device_wifi_psk}</div>
|
|
||||||
<div className="flex shadow-md rounded-md ml-2">
|
|
||||||
<input {...register('wifiPassword', {})} type="password" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div className="flex bg-gray-100 group p-1 cursor-pointer hover:bg-gray-200 border-b">
|
|
||||||
<button
|
|
||||||
type="submit"
|
|
||||||
className="flex m-auto font-medium group-hover:text-gray-700"
|
|
||||||
>
|
|
||||||
<SaveIcon className="m-auto mr-2 group-hover:text-gray-700 w-5 h-5" />
|
|
||||||
{props.translations.save_changes_button}
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
<JSONPretty data={preferences} />
|
|
||||||
</form>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default SettingsForm;
|
|
||||||
@@ -6,19 +6,16 @@ import {
|
|||||||
ChevronRightIcon,
|
ChevronRightIcon,
|
||||||
UsersIcon,
|
UsersIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
import type { Types } from '@meshtastic/meshtasticjs';
|
|
||||||
|
|
||||||
import type { languageTemplate } from '../../../App';
|
import { TranslationContext } from '../../../translations/TranslationContext';
|
||||||
import Node from './Node';
|
import NodeList from './NodeList';
|
||||||
|
|
||||||
interface NodesProps {
|
interface NodesProps {
|
||||||
isReady: boolean;
|
|
||||||
nodes: Types.NodeInfoPacket[];
|
|
||||||
translations: languageTemplate;
|
|
||||||
myId: number;
|
myId: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const Nodes = (props: NodesProps): JSX.Element => {
|
const Nodes = (props: NodesProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -31,21 +28,21 @@ const Nodes = (props: NodesProps): JSX.Element => {
|
|||||||
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
||||||
)}
|
)}
|
||||||
<UsersIcon className="my-auto text-gray-600 mr-2 w-5 h-5" />
|
<UsersIcon className="my-auto text-gray-600 mr-2 w-5 h-5" />
|
||||||
{props.translations.nodes_title}
|
{translations.nodes_title}
|
||||||
</div>
|
</div>
|
||||||
</Disclosure.Button>
|
</Disclosure.Button>
|
||||||
<Disclosure.Panel className="shadow-inner">
|
<Disclosure.Panel className="shadow-inner">
|
||||||
{props.nodes.length ? (
|
<React.Suspense
|
||||||
props.nodes.map((node, index) => (
|
fallback={
|
||||||
<Node key={index} node={node} myId={props.myId} />
|
<div className="flex border-b border-gray-300">
|
||||||
))
|
<div className="m-auto p-3 text-gray-500">
|
||||||
) : (
|
{translations.no_nodes_message}
|
||||||
<div className="flex border-b border-gray-300">
|
</div>
|
||||||
<div className="m-auto p-3 text-gray-500">
|
|
||||||
{props.translations.no_nodes_message}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
}
|
||||||
)}
|
>
|
||||||
|
<NodeList myId={props.myId} />
|
||||||
|
</React.Suspense>
|
||||||
</Disclosure.Panel>
|
</Disclosure.Panel>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|||||||
@@ -0,0 +1,46 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import { useObservableSuspense } from 'observable-hooks';
|
||||||
|
|
||||||
|
import type { Types } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
|
import { nodeResource } from '../../../streams';
|
||||||
|
import Node from './Node';
|
||||||
|
|
||||||
|
export interface NodeListProps {
|
||||||
|
myId: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NodeList = (props: NodeListProps): JSX.Element => {
|
||||||
|
const nodeSource = useObservableSuspense(nodeResource);
|
||||||
|
|
||||||
|
const [nodes, setNodes] = React.useState<Types.NodeInfoPacket[]>([]);
|
||||||
|
|
||||||
|
React.useEffect(() => {
|
||||||
|
if (
|
||||||
|
nodes.findIndex(
|
||||||
|
(currentNode) => currentNode.data.num === nodeSource.data.num,
|
||||||
|
) >= 0
|
||||||
|
) {
|
||||||
|
setNodes(
|
||||||
|
nodes.map((currentNode) =>
|
||||||
|
currentNode.data.num === nodeSource.data.num
|
||||||
|
? nodeSource
|
||||||
|
: currentNode,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
setNodes((nodes) => [...nodes, nodeSource]);
|
||||||
|
}
|
||||||
|
}, [nodeSource, nodes]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
{nodes.map((node, index) => (
|
||||||
|
<Node key={index} node={node} myId={props.myId} />
|
||||||
|
))}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default NodeList;
|
||||||
@@ -7,18 +7,19 @@ import {
|
|||||||
CogIcon,
|
CogIcon,
|
||||||
} from '@heroicons/react/outline';
|
} from '@heroicons/react/outline';
|
||||||
|
|
||||||
import type { LanguageEnum, languageTemplate } from '../../../App';
|
import type { LanguageEnum } from '../../../translations/TranslationContext';
|
||||||
|
import { TranslationContext } from '../../../translations/TranslationContext';
|
||||||
import Translations from './Translations';
|
import Translations from './Translations';
|
||||||
|
|
||||||
interface UIProps {
|
interface UIProps {
|
||||||
language: LanguageEnum;
|
language: LanguageEnum;
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
||||||
translations: languageTemplate;
|
|
||||||
darkmode: boolean;
|
darkmode: boolean;
|
||||||
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
setDarkmode: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const UI = (props: UIProps): JSX.Element => {
|
const UI = (props: UIProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -31,14 +32,13 @@ const UI = (props: UIProps): JSX.Element => {
|
|||||||
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
||||||
)}
|
)}
|
||||||
<CogIcon className="my-auto text-gray-600 mr-2 w-5 h-5" />
|
<CogIcon className="my-auto text-gray-600 mr-2 w-5 h-5" />
|
||||||
{props.translations.ui_settings_title}
|
{translations.ui_settings_title}
|
||||||
</div>
|
</div>
|
||||||
</Disclosure.Button>
|
</Disclosure.Button>
|
||||||
<Disclosure.Panel>
|
<Disclosure.Panel>
|
||||||
<Translations
|
<Translations
|
||||||
language={props.language}
|
language={props.language}
|
||||||
setLanguage={props.setLanguage}
|
setLanguage={props.setLanguage}
|
||||||
translations={props.translations}
|
|
||||||
/>
|
/>
|
||||||
</Disclosure.Panel>
|
</Disclosure.Panel>
|
||||||
</>
|
</>
|
||||||
|
|||||||
@@ -5,16 +5,18 @@ import { Br, Jp, Us } from 'react-flags-select';
|
|||||||
import { Disclosure } from '@headlessui/react';
|
import { Disclosure } from '@headlessui/react';
|
||||||
import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/outline';
|
import { ChevronDownIcon, ChevronRightIcon } from '@heroicons/react/outline';
|
||||||
|
|
||||||
import type { languageTemplate } from '../../../App';
|
import {
|
||||||
import { LanguageEnum } from '../../../App';
|
LanguageEnum,
|
||||||
|
TranslationContext,
|
||||||
|
} from '../../../translations/TranslationContext';
|
||||||
|
|
||||||
export interface TranslationsProps {
|
export interface TranslationsProps {
|
||||||
language: LanguageEnum;
|
language: LanguageEnum;
|
||||||
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
setLanguage: React.Dispatch<React.SetStateAction<LanguageEnum>>;
|
||||||
translations: languageTemplate;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const Translations = (props: TranslationsProps): JSX.Element => {
|
const Translations = (props: TranslationsProps): JSX.Element => {
|
||||||
|
const { translations } = React.useContext(TranslationContext);
|
||||||
return (
|
return (
|
||||||
<Disclosure>
|
<Disclosure>
|
||||||
{({ open }) => (
|
{({ open }) => (
|
||||||
@@ -26,7 +28,7 @@ const Translations = (props: TranslationsProps): JSX.Element => {
|
|||||||
) : (
|
) : (
|
||||||
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
<ChevronRightIcon className="my-auto w-5 h-5 mr-2" />
|
||||||
)}
|
)}
|
||||||
{props.translations.language_title}
|
{translations.language_title}
|
||||||
<div className="my-auto">
|
<div className="my-auto">
|
||||||
{props.language === LanguageEnum.ENGLISH ? (
|
{props.language === LanguageEnum.ENGLISH ? (
|
||||||
<Us className="ml-2 w-8" />
|
<Us className="ml-2 w-8" />
|
||||||
|
|||||||
+15
-1
@@ -7,13 +7,27 @@ import React from 'react';
|
|||||||
import ReactDOM from 'react-dom';
|
import ReactDOM from 'react-dom';
|
||||||
|
|
||||||
import App from './App';
|
import App from './App';
|
||||||
|
import Translations_English from './translations/en';
|
||||||
|
import {
|
||||||
|
LanguageEnum,
|
||||||
|
TranslationContext,
|
||||||
|
} from './translations/TranslationContext';
|
||||||
|
|
||||||
const element = document.getElementById('root');
|
const element = document.getElementById('root');
|
||||||
|
|
||||||
if (element) {
|
if (element) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-ignore
|
||||||
ReactDOM.createRoot(element).render(
|
ReactDOM.createRoot(element).render(
|
||||||
<React.StrictMode>
|
<React.StrictMode>
|
||||||
<App />
|
<TranslationContext.Provider
|
||||||
|
value={{
|
||||||
|
language: LanguageEnum.ENGLISH,
|
||||||
|
translations: Translations_English,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<App />
|
||||||
|
</TranslationContext.Provider>
|
||||||
</React.StrictMode>,
|
</React.StrictMode>,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { ObservableResource } from 'observable-hooks';
|
||||||
|
import { Subject } from 'rxjs';
|
||||||
|
|
||||||
|
import type { Protobuf, Types } from '@meshtastic/meshtasticjs';
|
||||||
|
|
||||||
|
export const preferencesSubject$ =
|
||||||
|
new Subject<Protobuf.RadioConfig_UserPreferences>();
|
||||||
|
|
||||||
|
export const preferencesResource = new ObservableResource(preferencesSubject$);
|
||||||
|
|
||||||
|
export const nodeSubject$ = new Subject<Types.NodeInfoPacket>();
|
||||||
|
|
||||||
|
export const nodeResource = new ObservableResource(nodeSubject$);
|
||||||
|
|
||||||
|
export const channelSubject$ = new Subject<Protobuf.Channel>();
|
||||||
|
|
||||||
|
export const channelResource = new ObservableResource(channelSubject$);
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
import Translations_English from './en';
|
||||||
|
|
||||||
|
export interface languageTemplate {
|
||||||
|
no_messages_message: string;
|
||||||
|
ui_settings_title: string;
|
||||||
|
nodes_title: string;
|
||||||
|
color_scheme_title: string;
|
||||||
|
language_title: string;
|
||||||
|
device_settings_title: string;
|
||||||
|
device_channels_title: string;
|
||||||
|
device_region_title: string;
|
||||||
|
device_wifi_ssid: string;
|
||||||
|
device_wifi_psk: string;
|
||||||
|
save_changes_button: string;
|
||||||
|
no_nodes_message: string;
|
||||||
|
no_message_placeholder: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LanguageEnum {
|
||||||
|
ENGLISH,
|
||||||
|
JAPANESE,
|
||||||
|
PORTUGUESE,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const TranslationContext = React.createContext({
|
||||||
|
language: LanguageEnum.ENGLISH,
|
||||||
|
translations: Translations_English,
|
||||||
|
});
|
||||||
|
|
||||||
|
// const TranslationProvider: React.FC = ({ children }) => {
|
||||||
|
// const [language, setLanguage] = React.useState<LanguageEnum>(
|
||||||
|
// LanguageEnum.ENGLISH,
|
||||||
|
// );
|
||||||
|
// return { children };
|
||||||
|
// };
|
||||||
|
|
||||||
|
// export default TranslationProvider;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { languageTemplate } from '../App';
|
import type { languageTemplate } from './TranslationContext';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
no_messages_message: 'No messages yet',
|
no_messages_message: 'No messages yet',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { languageTemplate } from '../App';
|
import type { languageTemplate } from './TranslationContext';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
no_messages_message: 'まだメッセージはありません',
|
no_messages_message: 'まだメッセージはありません',
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import type { languageTemplate } from '../App';
|
import type { languageTemplate } from './TranslationContext';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
no_messages_message: 'Não a mensagens ainda',
|
no_messages_message: 'Não a mensagens ainda',
|
||||||
|
|||||||
@@ -17,20 +17,7 @@
|
|||||||
"noEmit": true,
|
"noEmit": true,
|
||||||
/* Additional Options */
|
/* Additional Options */
|
||||||
"strict": true,
|
"strict": true,
|
||||||
"noImplicitAny": true,
|
|
||||||
"noImplicitThis": true,
|
|
||||||
"noUnusedLocals": true,
|
|
||||||
"noUnusedParameters": true,
|
|
||||||
"noImplicitReturns": true,
|
|
||||||
"noFallthroughCasesInSwitch": true,
|
|
||||||
// "noUncheckedIndexedAccess": true,
|
|
||||||
"noPropertyAccessFromIndexSignature": true,
|
|
||||||
"strictBindCallApply": true,
|
|
||||||
"strictFunctionTypes": true,
|
|
||||||
"strictNullChecks": true,
|
"strictNullChecks": true,
|
||||||
"strictPropertyInitialization": true,
|
|
||||||
"experimentalDecorators": true,
|
|
||||||
"emitDecoratorMetadata": true,
|
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
"forceConsistentCasingInFileNames": true,
|
"forceConsistentCasingInFileNames": true,
|
||||||
"resolveJsonModule": true,
|
"resolveJsonModule": true,
|
||||||
|
|||||||
@@ -259,13 +259,13 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.1.tgz#66d25f6441920bd5c2146ea27fd33995885452dd"
|
resolved "https://registry.yarnpkg.com/@heroicons/react/-/react-1.0.1.tgz#66d25f6441920bd5c2146ea27fd33995885452dd"
|
||||||
integrity sha512-uikw2gKCmqnvjVxitecWfFLMOKyL9BTFcU4VM3hHj9OMwpkCr5Ke+MRMyY2/aQVmsYs4VTq7NCFX05MYwAHi3g==
|
integrity sha512-uikw2gKCmqnvjVxitecWfFLMOKyL9BTFcU4VM3hHj9OMwpkCr5Ke+MRMyY2/aQVmsYs4VTq7NCFX05MYwAHi3g==
|
||||||
|
|
||||||
"@meshtastic/meshtasticjs@^0.6.12":
|
"@meshtastic/meshtasticjs@^0.6.13":
|
||||||
version "0.6.12"
|
version "0.6.13"
|
||||||
resolved "https://registry.yarnpkg.com/@meshtastic/meshtasticjs/-/meshtasticjs-0.6.12.tgz#10368d67d983fdedae46fc176bc9da07bb67e7e7"
|
resolved "https://registry.yarnpkg.com/@meshtastic/meshtasticjs/-/meshtasticjs-0.6.13.tgz#4e459a1380a8761dc119e5f43bbc42c18b18e5a1"
|
||||||
integrity sha512-Ys8odPrmWaLHcyzRE8+iQT2TCMIWPQXldIkEc7ydmAZO3Hc5Ol1pOHHsd/EMh9AvM/pR5ZhbSX2j8q5hBhG6UQ==
|
integrity sha512-NdS5Cx/da7NW2FXgWvk+3lyFh/iVV3KpoEFkTFOS06liPYty1eKJo/sZgfNd/7DfdiWEDeOq9UG4aAVVsIxnlw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@protobuf-ts/runtime" "^2.0.0-alpha.21"
|
"@protobuf-ts/runtime" "^2.0.0-alpha.25"
|
||||||
rxjs "^6.6.7"
|
rxjs "^7.1.0"
|
||||||
|
|
||||||
"@nodelib/fs.scandir@2.1.4":
|
"@nodelib/fs.scandir@2.1.4":
|
||||||
version "2.1.4"
|
version "2.1.4"
|
||||||
@@ -341,15 +341,10 @@
|
|||||||
node-gyp "^7.1.0"
|
node-gyp "^7.1.0"
|
||||||
read-package-json-fast "^2.0.1"
|
read-package-json-fast "^2.0.1"
|
||||||
|
|
||||||
"@protobuf-ts/runtime@^2.0.0-alpha.21":
|
"@protobuf-ts/runtime@^2.0.0-alpha.25":
|
||||||
version "2.0.0-alpha.21"
|
version "2.0.0-alpha.25"
|
||||||
resolved "https://registry.yarnpkg.com/@protobuf-ts/runtime/-/runtime-2.0.0-alpha.21.tgz#0814f365d1f155f55a83e13f38dba92856e66ec5"
|
resolved "https://registry.yarnpkg.com/@protobuf-ts/runtime/-/runtime-2.0.0-alpha.25.tgz#e8e7067c77ddf35a3e310ea93f58a58aa42e9bc2"
|
||||||
integrity sha512-m6Ohw3ke0RiCW41kKbkPW7z+wEgchX99iAwPjFMHRYEf1w1fX8IBIzANHe13lg2MP1P7zmZYGbQ5nupFqo4cWw==
|
integrity sha512-+N3Jj61AY8u0MxxaxtovLDWgVdTmOhDG4lDDyfRQPGFzpz+ACFEcTE6WRIj1xe62kbgyQFiWkIfPO1F/mHBF3g==
|
||||||
|
|
||||||
"@react-rxjs/core@^0.8.0":
|
|
||||||
version "0.8.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/@react-rxjs/core/-/core-0.8.0.tgz#b73c0480a457b654fdcd6d6ede36bbd99c691b2e"
|
|
||||||
integrity sha512-LvmVEel9MPykAJoI0oZafmui2JOU18bmIf0X0P+oEtVii0LNaj8p/3eL52NfWgsQd6hSrjevSwNbbrScsYuaFg==
|
|
||||||
|
|
||||||
"@snowpack/plugin-dotenv@^2.0.5":
|
"@snowpack/plugin-dotenv@^2.0.5":
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
@@ -402,7 +397,7 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4"
|
resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.47.tgz#d7a51db20f0650efec24cd04994f523d93172ed4"
|
||||||
integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==
|
integrity sha512-c5ciR06jK8u9BstrmJyO97m+klJrrhCf9u3rLu3DEAJBirxRqSCvDQoYKmxuYwQI5SZChAWu+tq9oVlGRuzPAg==
|
||||||
|
|
||||||
"@types/json-schema@*", "@types/json-schema@^7.0.3":
|
"@types/json-schema@*", "@types/json-schema@^7.0.7":
|
||||||
version "7.0.7"
|
version "7.0.7"
|
||||||
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
|
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.7.tgz#98a993516c859eb0d5c4c8f098317a9ea68db9ad"
|
||||||
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
|
integrity sha512-cxWFQVseBm6O9Gbw1IWb8r6OS4OhSt3hPZLkFApLjM8TEXROBuQGLAH2i2gZpcXdLBIrpXuTDhH7Vbm1iXmNGA==
|
||||||
@@ -457,74 +452,74 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/snowpack-env/-/snowpack-env-2.3.3.tgz#d2dfb1fb8557aa8bb517606d5dfa249cc861c3ff"
|
resolved "https://registry.yarnpkg.com/@types/snowpack-env/-/snowpack-env-2.3.3.tgz#d2dfb1fb8557aa8bb517606d5dfa249cc861c3ff"
|
||||||
integrity sha512-riJuu2fR3qhBfpWJtqQtNwYJFvquiXfqdprXvZjSNmscnZbIVyHoM49ZVEM1bciKM1mWOCdjXymOYHyGh2WLtg==
|
integrity sha512-riJuu2fR3qhBfpWJtqQtNwYJFvquiXfqdprXvZjSNmscnZbIVyHoM49ZVEM1bciKM1mWOCdjXymOYHyGh2WLtg==
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^4.25.0":
|
"@typescript-eslint/eslint-plugin@^4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.25.0.tgz#d82657b6ab4caa4c3f888ff923175fadc2f31f2a"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.26.0.tgz#12bbd6ebd5e7fabd32e48e1e60efa1f3554a3242"
|
||||||
integrity sha512-Qfs3dWkTMKkKwt78xp2O/KZQB8MPS1UQ5D3YW2s6LQWBE1074BE+Rym+b1pXZIX3M3fSvPUDaCvZLKV2ylVYYQ==
|
integrity sha512-yA7IWp+5Qqf+TLbd8b35ySFOFzUfL7i+4If50EqvjT6w35X8Lv0eBHb6rATeWmucks37w+zV+tWnOXI9JlG6Eg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/experimental-utils" "4.25.0"
|
"@typescript-eslint/experimental-utils" "4.26.0"
|
||||||
"@typescript-eslint/scope-manager" "4.25.0"
|
"@typescript-eslint/scope-manager" "4.26.0"
|
||||||
debug "^4.1.1"
|
debug "^4.3.1"
|
||||||
functional-red-black-tree "^1.0.1"
|
functional-red-black-tree "^1.0.1"
|
||||||
lodash "^4.17.15"
|
lodash "^4.17.21"
|
||||||
regexpp "^3.0.0"
|
regexpp "^3.1.0"
|
||||||
semver "^7.3.2"
|
semver "^7.3.5"
|
||||||
tsutils "^3.17.1"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/experimental-utils@4.25.0":
|
"@typescript-eslint/experimental-utils@4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.25.0.tgz#b2febcfa715d2c1806fd5f0335193a6cd270df54"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.26.0.tgz#ba7848b3f088659cdf71bce22454795fc55be99a"
|
||||||
integrity sha512-f0doRE76vq7NEEU0tw+ajv6CrmPelw5wLoaghEHkA2dNLFb3T/zJQqGPQ0OYt5XlZaS13MtnN+GTPCuUVg338w==
|
integrity sha512-TH2FO2rdDm7AWfAVRB5RSlbUhWxGVuxPNzGT7W65zVfl8H/WeXTk1e69IrcEVsBslrQSTDKQSaJD89hwKrhdkw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@types/json-schema" "^7.0.3"
|
"@types/json-schema" "^7.0.7"
|
||||||
"@typescript-eslint/scope-manager" "4.25.0"
|
"@typescript-eslint/scope-manager" "4.26.0"
|
||||||
"@typescript-eslint/types" "4.25.0"
|
"@typescript-eslint/types" "4.26.0"
|
||||||
"@typescript-eslint/typescript-estree" "4.25.0"
|
"@typescript-eslint/typescript-estree" "4.26.0"
|
||||||
eslint-scope "^5.0.0"
|
eslint-scope "^5.1.1"
|
||||||
eslint-utils "^2.0.0"
|
eslint-utils "^3.0.0"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^4.25.0":
|
"@typescript-eslint/parser@^4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.25.0.tgz#6b2cb6285aa3d55bfb263c650739091b0f19aceb"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.26.0.tgz#31b6b732c9454f757b020dab9b6754112aa5eeaf"
|
||||||
integrity sha512-OZFa1SKyEJpAhDx8FcbWyX+vLwh7OEtzoo2iQaeWwxucyfbi0mT4DijbOSsTgPKzGHr6GrF2V5p/CEpUH/VBxg==
|
integrity sha512-b4jekVJG9FfmjUfmM4VoOItQhPlnt6MPOBUL0AQbiTmm+SSpSdhHYlwayOm4IW9KLI/4/cRKtQCmDl1oE2OlPg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/scope-manager" "4.25.0"
|
"@typescript-eslint/scope-manager" "4.26.0"
|
||||||
"@typescript-eslint/types" "4.25.0"
|
"@typescript-eslint/types" "4.26.0"
|
||||||
"@typescript-eslint/typescript-estree" "4.25.0"
|
"@typescript-eslint/typescript-estree" "4.26.0"
|
||||||
debug "^4.1.1"
|
debug "^4.3.1"
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@4.25.0":
|
"@typescript-eslint/scope-manager@4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.25.0.tgz#9d86a5bcc46ef40acd03d85ad4e908e5aab8d4ca"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.26.0.tgz#60d1a71df162404e954b9d1c6343ff3bee496194"
|
||||||
integrity sha512-2NElKxMb/0rya+NJG1U71BuNnp1TBd1JgzYsldsdA83h/20Tvnf/HrwhiSlNmuq6Vqa0EzidsvkTArwoq+tH6w==
|
integrity sha512-G6xB6mMo4xVxwMt5lEsNTz3x4qGDt0NSGmTBNBPJxNsrTXJSm21c6raeYroS2OwQsOyIXqKZv266L/Gln1BWqg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "4.25.0"
|
"@typescript-eslint/types" "4.26.0"
|
||||||
"@typescript-eslint/visitor-keys" "4.25.0"
|
"@typescript-eslint/visitor-keys" "4.26.0"
|
||||||
|
|
||||||
"@typescript-eslint/types@4.25.0":
|
"@typescript-eslint/types@4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.25.0.tgz#0e444a5c5e3c22d7ffa5e16e0e60510b3de5af87"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.26.0.tgz#7c6732c0414f0a69595f4f846ebe12616243d546"
|
||||||
integrity sha512-+CNINNvl00OkW6wEsi32wU5MhHti2J25TJsJJqgQmJu3B3dYDBcmOxcE5w9cgoM13TrdE/5ND2HoEnBohasxRQ==
|
integrity sha512-rADNgXl1kS/EKnDr3G+m7fB9yeJNnR9kF7xMiXL6mSIWpr3Wg5MhxyfEXy/IlYthsqwBqHOr22boFbf/u6O88A==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@4.25.0":
|
"@typescript-eslint/typescript-estree@4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.25.0.tgz#942e4e25888736bff5b360d9b0b61e013d0cfa25"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.26.0.tgz#aea17a40e62dc31c63d5b1bbe9a75783f2ce7109"
|
||||||
integrity sha512-1B8U07TGNAFMxZbSpF6jqiDs1cVGO0izVkf18Q/SPcUAc9LhHxzvSowXDTvkHMWUVuPpagupaW63gB6ahTXVlg==
|
integrity sha512-GHUgahPcm9GfBuy3TzdsizCcPjKOAauG9xkz9TR8kOdssz2Iz9jRCSQm6+aVFa23d5NcSpo1GdHGSQKe0tlcbg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "4.25.0"
|
"@typescript-eslint/types" "4.26.0"
|
||||||
"@typescript-eslint/visitor-keys" "4.25.0"
|
"@typescript-eslint/visitor-keys" "4.26.0"
|
||||||
debug "^4.1.1"
|
debug "^4.3.1"
|
||||||
globby "^11.0.1"
|
globby "^11.0.3"
|
||||||
is-glob "^4.0.1"
|
is-glob "^4.0.1"
|
||||||
semver "^7.3.2"
|
semver "^7.3.5"
|
||||||
tsutils "^3.17.1"
|
tsutils "^3.21.0"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@4.25.0":
|
"@typescript-eslint/visitor-keys@4.26.0":
|
||||||
version "4.25.0"
|
version "4.26.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.25.0.tgz#863e7ed23da4287c5b469b13223255d0fde6aaa7"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.26.0.tgz#26d2583169222815be4dcd1da4fe5459bc3bcc23"
|
||||||
integrity sha512-AmkqV9dDJVKP/TcZrbf6s6i1zYXt5Hl8qOLrRDTFfRNae4+LB8A4N3i+FLZPW85zIxRy39BgeWOfMS3HoH5ngg==
|
integrity sha512-cw4j8lH38V1ycGBbF+aFiLUls9Z0Bw8QschP3mkth50BbWzgFS33ISIgBzUMuQ2IdahoEv/rXstr8Zhlz4B1Zg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "4.25.0"
|
"@typescript-eslint/types" "4.26.0"
|
||||||
eslint-visitor-keys "^2.0.0"
|
eslint-visitor-keys "^2.0.0"
|
||||||
|
|
||||||
abbrev@1:
|
abbrev@1:
|
||||||
@@ -780,10 +775,10 @@ binary-extensions@^2.0.0:
|
|||||||
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
|
||||||
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
|
||||||
|
|
||||||
boring-avatars@^1.5.4:
|
boring-avatars@^1.5.5:
|
||||||
version "1.5.4"
|
version "1.5.5"
|
||||||
resolved "https://registry.yarnpkg.com/boring-avatars/-/boring-avatars-1.5.4.tgz#4ca5608fb16b75322cf5e1bcdc49debfeb2dfd0d"
|
resolved "https://registry.yarnpkg.com/boring-avatars/-/boring-avatars-1.5.5.tgz#ea0b0f0f40299283586c31070ead7285956c0869"
|
||||||
integrity sha512-sSfAGVAjN0LNILSoQRT2zbG6Dy4j4WMqoDoydsU9xoIi9LKYae4DgaqRhCoGjn0iYRwsWtAu0PsohH1rLVPm+A==
|
integrity sha512-sIvumj2yscTQwcAdp/ANi4i97OKq5yPgXY6MfdHW4b6k6iljn9gFZa6TXgWyBnKXMPytx5e04mxrv7OCZKX9Wg==
|
||||||
|
|
||||||
bplist-parser@^0.1.0:
|
bplist-parser@^0.1.0:
|
||||||
version "0.1.1"
|
version "0.1.1"
|
||||||
@@ -1087,7 +1082,7 @@ dashdash@^1.12.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
assert-plus "^1.0.0"
|
assert-plus "^1.0.0"
|
||||||
|
|
||||||
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
|
debug@4, debug@^4.0.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1:
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
|
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee"
|
||||||
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ==
|
||||||
@@ -1438,7 +1433,7 @@ eslint-plugin-react@^7.24.0:
|
|||||||
resolve "^2.0.0-next.3"
|
resolve "^2.0.0-next.3"
|
||||||
string.prototype.matchall "^4.0.5"
|
string.prototype.matchall "^4.0.5"
|
||||||
|
|
||||||
eslint-scope@^5.0.0, eslint-scope@^5.1.1:
|
eslint-scope@^5.1.1:
|
||||||
version "5.1.1"
|
version "5.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c"
|
||||||
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==
|
||||||
@@ -1446,13 +1441,20 @@ eslint-scope@^5.0.0, eslint-scope@^5.1.1:
|
|||||||
esrecurse "^4.3.0"
|
esrecurse "^4.3.0"
|
||||||
estraverse "^4.1.1"
|
estraverse "^4.1.1"
|
||||||
|
|
||||||
eslint-utils@^2.0.0, eslint-utils@^2.1.0:
|
eslint-utils@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
|
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-2.1.0.tgz#d2de5e03424e707dc10c74068ddedae708741b27"
|
||||||
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
|
integrity sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==
|
||||||
dependencies:
|
dependencies:
|
||||||
eslint-visitor-keys "^1.1.0"
|
eslint-visitor-keys "^1.1.0"
|
||||||
|
|
||||||
|
eslint-utils@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672"
|
||||||
|
integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==
|
||||||
|
dependencies:
|
||||||
|
eslint-visitor-keys "^2.0.0"
|
||||||
|
|
||||||
eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
|
eslint-visitor-keys@^1.1.0, eslint-visitor-keys@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz#30ebd1ef7c2fdff01c3a4f151044af25fab0523e"
|
||||||
@@ -1828,7 +1830,7 @@ globals@^13.6.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
type-fest "^0.20.2"
|
type-fest "^0.20.2"
|
||||||
|
|
||||||
globby@^11.0.0, globby@^11.0.1:
|
globby@^11.0.0, globby@^11.0.3:
|
||||||
version "11.0.3"
|
version "11.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
|
resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.3.tgz#9b1f0cb523e171dd1ad8c7b2a9fb4b644b9593cb"
|
||||||
integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
|
integrity sha512-ffdmosjA807y7+lA1NM0jELARVmYul/715xiILEjo3hBLPTcirgQNnXECn5g3mtR8TOLCVbkfua1Hpen25/Xcg==
|
||||||
@@ -2469,7 +2471,7 @@ lodash.truncate@^4.4.2:
|
|||||||
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193"
|
||||||
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
|
integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=
|
||||||
|
|
||||||
lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.21:
|
lodash@^4.17.19, lodash@^4.17.21:
|
||||||
version "4.17.21"
|
version "4.17.21"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||||
@@ -3396,7 +3398,7 @@ regexp.prototype.flags@^1.3.0, regexp.prototype.flags@^1.3.1:
|
|||||||
call-bind "^1.0.2"
|
call-bind "^1.0.2"
|
||||||
define-properties "^1.1.3"
|
define-properties "^1.1.3"
|
||||||
|
|
||||||
regexpp@^3.0.0, regexpp@^3.1.0:
|
regexpp@^3.1.0:
|
||||||
version "3.1.0"
|
version "3.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
|
resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.1.0.tgz#206d0ad0a5648cffbdb8ae46438f3dc51c9f78e2"
|
||||||
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
|
integrity sha512-ZOIzd8yVsQQA7j8GCSlPGXwg5PfmA1mrq0JP4nGhh54LaKN3xdai/vHUDu74pKwV8OxseMS65u2NImosQcSD0Q==
|
||||||
@@ -3494,13 +3496,6 @@ run-parallel@^1.1.9:
|
|||||||
dependencies:
|
dependencies:
|
||||||
queue-microtask "^1.2.2"
|
queue-microtask "^1.2.2"
|
||||||
|
|
||||||
rxjs@^6.6.7:
|
|
||||||
version "6.6.7"
|
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9"
|
|
||||||
integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==
|
|
||||||
dependencies:
|
|
||||||
tslib "^1.9.0"
|
|
||||||
|
|
||||||
rxjs@^7.1.0:
|
rxjs@^7.1.0:
|
||||||
version "7.1.0"
|
version "7.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.1.0.tgz#94202d27b19305ef7b1a4f330277b2065df7039e"
|
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.1.0.tgz#94202d27b19305ef7b1a4f330277b2065df7039e"
|
||||||
@@ -3912,7 +3907,7 @@ tsconfig-paths@^3.9.0:
|
|||||||
minimist "^1.2.0"
|
minimist "^1.2.0"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
tslib@^1.8.1, tslib@^1.9.0:
|
tslib@^1.8.1:
|
||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
|
||||||
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
|
||||||
@@ -3922,7 +3917,7 @@ tslib@~2.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
|
||||||
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
|
||||||
|
|
||||||
tsutils@^3.17.1:
|
tsutils@^3.21.0:
|
||||||
version "3.21.0"
|
version "3.21.0"
|
||||||
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623"
|
||||||
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
|
integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==
|
||||||
|
|||||||
Reference in New Issue
Block a user