mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-08 17:53:10 +02:00
Remove some unneeded code
This commit is contained in:
@@ -119,7 +119,6 @@ A web interface for MeshCore mesh radio networks. The backend connects to a Mesh
|
|||||||
├── references/meshcore_py/ # MeshCore Python library
|
├── references/meshcore_py/ # MeshCore Python library
|
||||||
├── tests/ # Backend tests (pytest)
|
├── tests/ # Backend tests (pytest)
|
||||||
├── data/ # SQLite database (runtime)
|
├── data/ # SQLite database (runtime)
|
||||||
├── integration_test.html # Browser-based API tests
|
|
||||||
└── pyproject.toml # Python dependencies
|
└── pyproject.toml # Python dependencies
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -184,10 +183,6 @@ cd frontend
|
|||||||
npm run test:run
|
npm run test:run
|
||||||
```
|
```
|
||||||
|
|
||||||
### Integration Tests
|
|
||||||
|
|
||||||
Open `integration_test.html` in a browser with the backend running.
|
|
||||||
|
|
||||||
### Before Completing Changes
|
### Before Completing Changes
|
||||||
|
|
||||||
**Always run both backend and frontend validation before finishing any changes:**
|
**Always run both backend and frontend validation before finishing any changes:**
|
||||||
|
|||||||
@@ -159,24 +159,6 @@ class ContactRepository:
|
|||||||
)
|
)
|
||||||
await db.conn.commit()
|
await db.conn.commit()
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def clear_all_on_radio() -> None:
|
|
||||||
"""Clear the on_radio flag for all contacts."""
|
|
||||||
await db.conn.execute("UPDATE contacts SET on_radio = 0")
|
|
||||||
await db.conn.commit()
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def set_multiple_on_radio(public_keys: list[str], on_radio: bool = True) -> None:
|
|
||||||
"""Set on_radio flag for multiple contacts."""
|
|
||||||
if not public_keys:
|
|
||||||
return
|
|
||||||
placeholders = ",".join("?" * len(public_keys))
|
|
||||||
await db.conn.execute(
|
|
||||||
f"UPDATE contacts SET on_radio = ? WHERE public_key IN ({placeholders})",
|
|
||||||
[on_radio] + public_keys,
|
|
||||||
)
|
|
||||||
await db.conn.commit()
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def update_last_read_at(public_key: str, timestamp: int | None = None) -> bool:
|
async def update_last_read_at(public_key: str, timestamp: int | None = None) -> bool:
|
||||||
"""Update the last_read_at timestamp for a contact.
|
"""Update the last_read_at timestamp for a contact.
|
||||||
@@ -244,24 +226,6 @@ class ChannelRepository:
|
|||||||
for row in rows
|
for row in rows
|
||||||
]
|
]
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
async def get_by_name(name: str) -> Channel | None:
|
|
||||||
"""Get a channel by name."""
|
|
||||||
cursor = await db.conn.execute(
|
|
||||||
"SELECT key, name, is_hashtag, on_radio, last_read_at FROM channels WHERE name = ?",
|
|
||||||
(name,),
|
|
||||||
)
|
|
||||||
row = await cursor.fetchone()
|
|
||||||
if row:
|
|
||||||
return Channel(
|
|
||||||
key=row["key"],
|
|
||||||
name=row["name"],
|
|
||||||
is_hashtag=bool(row["is_hashtag"]),
|
|
||||||
on_radio=bool(row["on_radio"]),
|
|
||||||
last_read_at=row["last_read_at"],
|
|
||||||
)
|
|
||||||
return None
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def delete(key: str) -> None:
|
async def delete(key: str) -> None:
|
||||||
"""Delete a channel by key."""
|
"""Delete a channel by key."""
|
||||||
|
|||||||
+1
-1
File diff suppressed because one or more lines are too long
+13
-13
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
-1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -13,8 +13,8 @@
|
|||||||
<link rel="shortcut icon" href="/favicon.ico" />
|
<link rel="shortcut icon" href="/favicon.ico" />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
||||||
<link rel="manifest" href="/site.webmanifest" />
|
<link rel="manifest" href="/site.webmanifest" />
|
||||||
<script type="module" crossorigin src="/assets/index-sgUM1Nqn.js"></script>
|
<script type="module" crossorigin src="/assets/index-DsqXtGVx.js"></script>
|
||||||
<link rel="stylesheet" crossorigin href="/assets/index-BsZWFlnF.css">
|
<link rel="stylesheet" crossorigin href="/assets/index-Cxcg9Mr6.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
@@ -93,16 +93,6 @@ export const api = {
|
|||||||
// Contacts
|
// Contacts
|
||||||
getContacts: (limit = 100, offset = 0) =>
|
getContacts: (limit = 100, offset = 0) =>
|
||||||
fetchJson<Contact[]>(`/contacts?limit=${limit}&offset=${offset}`),
|
fetchJson<Contact[]>(`/contacts?limit=${limit}&offset=${offset}`),
|
||||||
getContact: (publicKey: string) => fetchJson<Contact>(`/contacts/${publicKey}`),
|
|
||||||
syncContacts: () => fetchJson<{ synced: number }>('/contacts/sync', { method: 'POST' }),
|
|
||||||
addContactToRadio: (publicKey: string) =>
|
|
||||||
fetchJson<{ status: string }>(`/contacts/${publicKey}/add-to-radio`, {
|
|
||||||
method: 'POST',
|
|
||||||
}),
|
|
||||||
removeContactFromRadio: (publicKey: string) =>
|
|
||||||
fetchJson<{ status: string }>(`/contacts/${publicKey}/remove-from-radio`, {
|
|
||||||
method: 'POST',
|
|
||||||
}),
|
|
||||||
deleteContact: (publicKey: string) =>
|
deleteContact: (publicKey: string) =>
|
||||||
fetchJson<{ status: string }>(`/contacts/${publicKey}`, {
|
fetchJson<{ status: string }>(`/contacts/${publicKey}`, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
@@ -129,13 +119,11 @@ export const api = {
|
|||||||
|
|
||||||
// Channels
|
// Channels
|
||||||
getChannels: () => fetchJson<Channel[]>('/channels'),
|
getChannels: () => fetchJson<Channel[]>('/channels'),
|
||||||
getChannel: (key: string) => fetchJson<Channel>(`/channels/${key}`),
|
|
||||||
createChannel: (name: string, key?: string) =>
|
createChannel: (name: string, key?: string) =>
|
||||||
fetchJson<Channel>('/channels', {
|
fetchJson<Channel>('/channels', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
body: JSON.stringify({ name, key }),
|
body: JSON.stringify({ name, key }),
|
||||||
}),
|
}),
|
||||||
syncChannels: () => fetchJson<{ synced: number }>('/channels/sync', { method: 'POST' }),
|
|
||||||
deleteChannel: (key: string) =>
|
deleteChannel: (key: string) =>
|
||||||
fetchJson<{ status: string }>(`/channels/${key}`, { method: 'DELETE' }),
|
fetchJson<{ status: string }>(`/channels/${key}`, { method: 'DELETE' }),
|
||||||
markChannelRead: (key: string) =>
|
markChannelRead: (key: string) =>
|
||||||
@@ -215,16 +203,6 @@ export const api = {
|
|||||||
}),
|
}),
|
||||||
|
|
||||||
// Favorites
|
// Favorites
|
||||||
addFavorite: (type: Favorite['type'], id: string) =>
|
|
||||||
fetchJson<AppSettings>('/settings/favorites', {
|
|
||||||
method: 'POST',
|
|
||||||
body: JSON.stringify({ type, id }),
|
|
||||||
}),
|
|
||||||
removeFavorite: (type: Favorite['type'], id: string) =>
|
|
||||||
fetchJson<AppSettings>('/settings/favorites', {
|
|
||||||
method: 'DELETE',
|
|
||||||
body: JSON.stringify({ type, id }),
|
|
||||||
}),
|
|
||||||
toggleFavorite: (type: Favorite['type'], id: string) =>
|
toggleFavorite: (type: Favorite['type'], id: string) =>
|
||||||
fetchJson<AppSettings>('/settings/favorites/toggle', {
|
fetchJson<AppSettings>('/settings/favorites/toggle', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
|
|||||||
@@ -1,50 +0,0 @@
|
|||||||
import * as React from 'react';
|
|
||||||
import { cva, type VariantProps } from 'class-variance-authority';
|
|
||||||
|
|
||||||
import { cn } from '@/lib/utils';
|
|
||||||
|
|
||||||
const alertVariants = cva(
|
|
||||||
'relative w-full rounded-lg border p-4 [&>svg~*]:pl-7 [&>svg+div]:translate-y-[-3px] [&>svg]:absolute [&>svg]:left-4 [&>svg]:top-4 [&>svg]:text-foreground',
|
|
||||||
{
|
|
||||||
variants: {
|
|
||||||
variant: {
|
|
||||||
default: 'bg-background text-foreground',
|
|
||||||
destructive:
|
|
||||||
'border-destructive/50 text-destructive dark:border-destructive [&>svg]:text-destructive',
|
|
||||||
warning: 'border-yellow-500/50 bg-yellow-500/10 text-yellow-200 [&>svg]:text-yellow-500',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
defaultVariants: {
|
|
||||||
variant: 'default',
|
|
||||||
},
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const Alert = React.forwardRef<
|
|
||||||
HTMLDivElement,
|
|
||||||
React.HTMLAttributes<HTMLDivElement> & VariantProps<typeof alertVariants>
|
|
||||||
>(({ className, variant, ...props }, ref) => (
|
|
||||||
<div ref={ref} role="alert" className={cn(alertVariants({ variant }), className)} {...props} />
|
|
||||||
));
|
|
||||||
Alert.displayName = 'Alert';
|
|
||||||
|
|
||||||
const AlertTitle = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<HTMLHeadingElement>>(
|
|
||||||
({ className, ...props }, ref) => (
|
|
||||||
<h5
|
|
||||||
ref={ref}
|
|
||||||
className={cn('mb-1 font-medium leading-none tracking-tight', className)}
|
|
||||||
{...props}
|
|
||||||
/>
|
|
||||||
)
|
|
||||||
);
|
|
||||||
AlertTitle.displayName = 'AlertTitle';
|
|
||||||
|
|
||||||
const AlertDescription = React.forwardRef<
|
|
||||||
HTMLParagraphElement,
|
|
||||||
React.HTMLAttributes<HTMLParagraphElement>
|
|
||||||
>(({ className, ...props }, ref) => (
|
|
||||||
<div ref={ref} className={cn('text-sm [&_p]:leading-relaxed', className)} {...props} />
|
|
||||||
));
|
|
||||||
AlertDescription.displayName = 'AlertDescription';
|
|
||||||
|
|
||||||
export { Alert, AlertTitle, AlertDescription };
|
|
||||||
@@ -1,11 +1,4 @@
|
|||||||
export {
|
export { useRepeaterMode, type UseRepeaterModeResult } from './useRepeaterMode';
|
||||||
useRepeaterMode,
|
|
||||||
type UseRepeaterModeResult,
|
|
||||||
formatDuration,
|
|
||||||
formatTelemetry,
|
|
||||||
formatNeighbors,
|
|
||||||
formatAcl,
|
|
||||||
} from './useRepeaterMode';
|
|
||||||
export { useUnreadCounts, type UseUnreadCountsResult } from './useUnreadCounts';
|
export { useUnreadCounts, type UseUnreadCountsResult } from './useUnreadCounts';
|
||||||
export {
|
export {
|
||||||
useConversationMessages,
|
useConversationMessages,
|
||||||
|
|||||||
@@ -6,9 +6,6 @@
|
|||||||
/** 64-character hex string identifying a contact/node */
|
/** 64-character hex string identifying a contact/node */
|
||||||
export type PublicKey = string;
|
export type PublicKey = string;
|
||||||
|
|
||||||
/** 12-character hex prefix of a public key (used in message routing) */
|
|
||||||
export type PubkeyPrefix = string;
|
|
||||||
|
|
||||||
/** 32-character hex string identifying a channel */
|
/** 32-character hex string identifying a channel */
|
||||||
export type ChannelKey = string;
|
export type ChannelKey = string;
|
||||||
|
|
||||||
|
|||||||
@@ -7,11 +7,8 @@
|
|||||||
* module provides utilities for working with both formats consistently.
|
* module provides utilities for working with both formats consistently.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** Length of a full public key in hex characters */
|
|
||||||
export const PUBKEY_FULL_LENGTH = 64;
|
|
||||||
|
|
||||||
/** Length of a public key prefix in hex characters */
|
/** Length of a public key prefix in hex characters */
|
||||||
export const PUBKEY_PREFIX_LENGTH = 12;
|
const PUBKEY_PREFIX_LENGTH = 12;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract the 12-character prefix from a public key.
|
* Extract the 12-character prefix from a public key.
|
||||||
@@ -21,42 +18,9 @@ export function getPubkeyPrefix(key: string): string {
|
|||||||
return key.slice(0, PUBKEY_PREFIX_LENGTH);
|
return key.slice(0, PUBKEY_PREFIX_LENGTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if two public keys match by comparing their prefixes.
|
|
||||||
* This handles the case where one key is full (64 chars) and
|
|
||||||
* the other is a prefix (12 chars).
|
|
||||||
*/
|
|
||||||
export function pubkeysMatch(a: string, b: string): boolean {
|
|
||||||
if (!a || !b) return false;
|
|
||||||
return getPubkeyPrefix(a) === getPubkeyPrefix(b);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a public key starts with the given prefix.
|
|
||||||
* More explicit than using .startsWith() directly.
|
|
||||||
*/
|
|
||||||
export function pubkeyMatchesPrefix(fullKey: string, prefix: string): boolean {
|
|
||||||
if (!fullKey || !prefix) return false;
|
|
||||||
return fullKey.startsWith(prefix);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a display name for a contact, falling back to pubkey prefix.
|
* Get a display name for a contact, falling back to pubkey prefix.
|
||||||
*/
|
*/
|
||||||
export function getContactDisplayName(name: string | null | undefined, pubkey: string): string {
|
export function getContactDisplayName(name: string | null | undefined, pubkey: string): string {
|
||||||
return name || getPubkeyPrefix(pubkey);
|
return name || getPubkeyPrefix(pubkey);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a key is a full 64-character public key.
|
|
||||||
*/
|
|
||||||
export function isFullPubkey(key: string): boolean {
|
|
||||||
return key.length === PUBKEY_FULL_LENGTH;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Check if a key is a 12-character prefix.
|
|
||||||
*/
|
|
||||||
export function isPubkeyPrefix(key: string): boolean {
|
|
||||||
return key.length === PUBKEY_PREFIX_LENGTH;
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user