mirror of
https://github.com/jkingsman/Remote-Terminal-for-MeshCore.git
synced 2026-08-02 06:53:09 +02:00
Add ability to pause radio connection (closes #51)
This commit is contained in:
@@ -31,6 +31,8 @@ interface SettingsModalBaseProps {
|
||||
onSaveAppSettings: (update: AppSettingsUpdate) => Promise<void>;
|
||||
onSetPrivateKey: (key: string) => Promise<void>;
|
||||
onReboot: () => Promise<void>;
|
||||
onDisconnect: () => Promise<void>;
|
||||
onReconnect: () => Promise<void>;
|
||||
onAdvertise: () => Promise<void>;
|
||||
onHealthRefresh: () => Promise<void>;
|
||||
onRefreshAppSettings: () => Promise<void>;
|
||||
@@ -59,6 +61,8 @@ export function SettingsModal(props: SettingsModalProps) {
|
||||
onSaveAppSettings,
|
||||
onSetPrivateKey,
|
||||
onReboot,
|
||||
onDisconnect,
|
||||
onReconnect,
|
||||
onAdvertise,
|
||||
onHealthRefresh,
|
||||
onRefreshAppSettings,
|
||||
@@ -182,6 +186,8 @@ export function SettingsModal(props: SettingsModalProps) {
|
||||
onSaveAppSettings={onSaveAppSettings}
|
||||
onSetPrivateKey={onSetPrivateKey}
|
||||
onReboot={onReboot}
|
||||
onDisconnect={onDisconnect}
|
||||
onReconnect={onReconnect}
|
||||
onAdvertise={onAdvertise}
|
||||
onClose={onClose}
|
||||
className={sectionContentClass}
|
||||
|
||||
@@ -22,13 +22,24 @@ export function StatusBar({
|
||||
onSettingsClick,
|
||||
onMenuClick,
|
||||
}: StatusBarProps) {
|
||||
const radioState =
|
||||
health?.radio_state ??
|
||||
(health?.radio_initializing
|
||||
? 'initializing'
|
||||
: health?.radio_connected
|
||||
? 'connected'
|
||||
: 'disconnected');
|
||||
const connected = health?.radio_connected ?? false;
|
||||
const initializing = health?.radio_initializing ?? false;
|
||||
const statusLabel = initializing
|
||||
? 'Radio Initializing'
|
||||
: connected
|
||||
? 'Radio OK'
|
||||
: 'Radio Disconnected';
|
||||
const statusLabel =
|
||||
radioState === 'paused'
|
||||
? 'Radio Paused'
|
||||
: radioState === 'connecting'
|
||||
? 'Radio Connecting'
|
||||
: radioState === 'initializing'
|
||||
? 'Radio Initializing'
|
||||
: connected
|
||||
? 'Radio OK'
|
||||
: 'Radio Disconnected';
|
||||
const [reconnecting, setReconnecting] = useState(false);
|
||||
const [currentTheme, setCurrentTheme] = useState(getSavedTheme);
|
||||
|
||||
@@ -97,7 +108,7 @@ export function StatusBar({
|
||||
<div
|
||||
className={cn(
|
||||
'w-2 h-2 rounded-full transition-colors',
|
||||
initializing
|
||||
radioState === 'initializing' || radioState === 'connecting'
|
||||
? 'bg-warning'
|
||||
: connected
|
||||
? 'bg-status-connected shadow-[0_0_6px_hsl(var(--status-connected)/0.5)]'
|
||||
@@ -128,13 +139,13 @@ export function StatusBar({
|
||||
</div>
|
||||
)}
|
||||
|
||||
{!connected && !initializing && (
|
||||
{(radioState === 'disconnected' || radioState === 'paused') && (
|
||||
<button
|
||||
onClick={handleReconnect}
|
||||
disabled={reconnecting}
|
||||
className="px-3 py-1 bg-warning/10 border border-warning/20 text-warning rounded-md text-xs cursor-pointer hover:bg-warning/15 transition-colors disabled:opacity-50 disabled:cursor-not-allowed focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
||||
>
|
||||
{reconnecting ? 'Reconnecting...' : 'Reconnect'}
|
||||
{reconnecting ? 'Reconnecting...' : radioState === 'paused' ? 'Connect' : 'Reconnect'}
|
||||
</button>
|
||||
)}
|
||||
<button
|
||||
|
||||
@@ -24,6 +24,8 @@ export function SettingsRadioSection({
|
||||
onSaveAppSettings,
|
||||
onSetPrivateKey,
|
||||
onReboot,
|
||||
onDisconnect,
|
||||
onReconnect,
|
||||
onAdvertise,
|
||||
onClose,
|
||||
className,
|
||||
@@ -36,6 +38,8 @@ export function SettingsRadioSection({
|
||||
onSaveAppSettings: (update: AppSettingsUpdate) => Promise<void>;
|
||||
onSetPrivateKey: (key: string) => Promise<void>;
|
||||
onReboot: () => Promise<void>;
|
||||
onDisconnect: () => Promise<void>;
|
||||
onReconnect: () => Promise<void>;
|
||||
onAdvertise: () => Promise<void>;
|
||||
onClose: () => void;
|
||||
className?: string;
|
||||
@@ -70,6 +74,7 @@ export function SettingsRadioSection({
|
||||
|
||||
// Advertise state
|
||||
const [advertising, setAdvertising] = useState(false);
|
||||
const [connectionBusy, setConnectionBusy] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setName(config.name);
|
||||
@@ -285,24 +290,82 @@ export function SettingsRadioSection({
|
||||
}
|
||||
};
|
||||
|
||||
const radioState =
|
||||
health?.radio_state ?? (health?.radio_initializing ? 'initializing' : 'disconnected');
|
||||
const connectionActionLabel =
|
||||
radioState === 'paused'
|
||||
? 'Reconnect'
|
||||
: radioState === 'connected' || radioState === 'initializing'
|
||||
? 'Disconnect'
|
||||
: 'Stop Trying';
|
||||
|
||||
const connectionStatusLabel =
|
||||
radioState === 'connected'
|
||||
? health?.connection_info || 'Connected'
|
||||
: radioState === 'initializing'
|
||||
? `Initializing ${health?.connection_info || 'radio'}`
|
||||
: radioState === 'connecting'
|
||||
? `Attempting to connect${health?.connection_info ? ` to ${health.connection_info}` : ''}`
|
||||
: radioState === 'paused'
|
||||
? `Connection paused${health?.connection_info ? ` (${health.connection_info})` : ''}`
|
||||
: 'Not connected';
|
||||
|
||||
const handleConnectionAction = async () => {
|
||||
setConnectionBusy(true);
|
||||
try {
|
||||
if (radioState === 'paused') {
|
||||
await onReconnect();
|
||||
toast.success('Reconnect requested');
|
||||
} else {
|
||||
await onDisconnect();
|
||||
toast.success('Radio connection paused');
|
||||
}
|
||||
} catch (err) {
|
||||
toast.error('Failed to change radio connection state', {
|
||||
description: err instanceof Error ? err.message : 'Check radio connection and try again',
|
||||
});
|
||||
} finally {
|
||||
setConnectionBusy(false);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
{/* Connection display */}
|
||||
<div className="space-y-2">
|
||||
<div className="space-y-3">
|
||||
<Label>Connection</Label>
|
||||
{health?.connection_info ? (
|
||||
<div className="flex items-center gap-2">
|
||||
<div className="w-2 h-2 rounded-full bg-status-connected" />
|
||||
<code className="px-2 py-1 bg-muted rounded text-foreground text-sm">
|
||||
{health.connection_info}
|
||||
</code>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex items-center gap-2 text-muted-foreground">
|
||||
<div className="w-2 h-2 rounded-full bg-status-disconnected" />
|
||||
<span>Not connected</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center gap-2">
|
||||
<div
|
||||
className={`w-2 h-2 rounded-full ${
|
||||
radioState === 'connected'
|
||||
? 'bg-status-connected'
|
||||
: radioState === 'initializing' || radioState === 'connecting'
|
||||
? 'bg-warning'
|
||||
: 'bg-status-disconnected'
|
||||
}`}
|
||||
/>
|
||||
<span
|
||||
className={
|
||||
radioState === 'paused' || radioState === 'disconnected'
|
||||
? 'text-muted-foreground'
|
||||
: ''
|
||||
}
|
||||
>
|
||||
{connectionStatusLabel}
|
||||
</span>
|
||||
</div>
|
||||
<Button
|
||||
type="button"
|
||||
variant="outline"
|
||||
onClick={handleConnectionAction}
|
||||
disabled={connectionBusy}
|
||||
className="w-full"
|
||||
>
|
||||
{connectionBusy ? `${connectionActionLabel}...` : connectionActionLabel}
|
||||
</Button>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Disconnect pauses automatic reconnect attempts so another device can use the radio.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{/* Radio Name */}
|
||||
|
||||
Reference in New Issue
Block a user