Switch to double quotes and reformat codebase with Biome
This commit is contained in:
@@ -65,7 +65,9 @@ export function DesktopPermissionRow({
|
||||
{isRequesting ? "Requesting..." : "Request"}
|
||||
</Button>
|
||||
)}
|
||||
{shouldShowDetail ? <Text style={styles.permissionDetailText}>{status?.detail}</Text> : null}
|
||||
{shouldShowDetail ? (
|
||||
<Text style={styles.permissionDetailText}>{status?.detail}</Text>
|
||||
) : null}
|
||||
</View>
|
||||
</View>
|
||||
);
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { ActivityIndicator, Alert, Image, Text, View } from 'react-native'
|
||||
import * as Clipboard from 'expo-clipboard'
|
||||
import * as QRCode from 'qrcode'
|
||||
import { useFocusEffect } from '@react-navigation/native'
|
||||
import { StyleSheet, useUnistyles } from 'react-native-unistyles'
|
||||
import { settingsStyles } from '@/styles/settings'
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { ActivityIndicator, Alert, Image, Text, View } from "react-native";
|
||||
import * as Clipboard from "expo-clipboard";
|
||||
import * as QRCode from "qrcode";
|
||||
import { useFocusEffect } from "@react-navigation/native";
|
||||
import { StyleSheet, useUnistyles } from "react-native-unistyles";
|
||||
import { settingsStyles } from "@/styles/settings";
|
||||
import {
|
||||
ArrowUpRight,
|
||||
Play,
|
||||
@@ -14,13 +14,13 @@ import {
|
||||
Copy,
|
||||
FileText,
|
||||
Smartphone,
|
||||
} from 'lucide-react-native'
|
||||
import { AdaptiveModalSheet } from '@/components/adaptive-modal-sheet'
|
||||
import { Button } from '@/components/ui/button'
|
||||
import { useAppSettings } from '@/hooks/use-settings'
|
||||
import { confirmDialog } from '@/utils/confirm-dialog'
|
||||
import { openExternalUrl } from '@/utils/open-external-url'
|
||||
import { getLocalDaemonVersion, isVersionMismatch } from '@/desktop/updates/desktop-updates'
|
||||
} from "lucide-react-native";
|
||||
import { AdaptiveModalSheet } from "@/components/adaptive-modal-sheet";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { useAppSettings } from "@/hooks/use-settings";
|
||||
import { confirmDialog } from "@/utils/confirm-dialog";
|
||||
import { openExternalUrl } from "@/utils/open-external-url";
|
||||
import { getLocalDaemonVersion, isVersionMismatch } from "@/desktop/updates/desktop-updates";
|
||||
import {
|
||||
getCliSymlinkInstructions,
|
||||
getDesktopDaemonLogs,
|
||||
@@ -34,291 +34,289 @@ import {
|
||||
type DesktopDaemonLogs,
|
||||
type DesktopDaemonStatus,
|
||||
type DesktopPairingOffer,
|
||||
} from '@/desktop/daemon/desktop-daemon'
|
||||
} from "@/desktop/daemon/desktop-daemon";
|
||||
|
||||
export interface LocalDaemonSectionProps {
|
||||
appVersion: string | null
|
||||
showLifecycleControls: boolean
|
||||
appVersion: string | null;
|
||||
showLifecycleControls: boolean;
|
||||
}
|
||||
|
||||
export function LocalDaemonSection({
|
||||
appVersion,
|
||||
showLifecycleControls,
|
||||
}: LocalDaemonSectionProps) {
|
||||
const { theme } = useUnistyles()
|
||||
const showSection = shouldUseDesktopDaemon()
|
||||
const { settings, updateSettings } = useAppSettings()
|
||||
const [daemonStatus, setDaemonStatus] = useState<DesktopDaemonStatus | null>(null)
|
||||
const [daemonVersion, setDaemonVersion] = useState<string | null>(null)
|
||||
const [statusError, setStatusError] = useState<string | null>(null)
|
||||
const [isRestartingDaemon, setIsRestartingDaemon] = useState(false)
|
||||
const [isUpdatingDaemonManagement, setIsUpdatingDaemonManagement] = useState(false)
|
||||
const [isLoadingCliSymlinkInstructions, setIsLoadingCliSymlinkInstructions] = useState(false)
|
||||
const [statusMessage, setStatusMessage] = useState<string | null>(null)
|
||||
const [cliStatusMessage, setCliStatusMessage] = useState<string | null>(null)
|
||||
const [daemonLogs, setDaemonLogs] = useState<DesktopDaemonLogs | null>(null)
|
||||
const [isLogsModalOpen, setIsLogsModalOpen] = useState(false)
|
||||
const [isPairingModalOpen, setIsPairingModalOpen] = useState(false)
|
||||
const [isCliSymlinkModalOpen, setIsCliSymlinkModalOpen] = useState(false)
|
||||
const [isLoadingPairing, setIsLoadingPairing] = useState(false)
|
||||
const [pairingOffer, setPairingOffer] = useState<DesktopPairingOffer | null>(null)
|
||||
export function LocalDaemonSection({ appVersion, showLifecycleControls }: LocalDaemonSectionProps) {
|
||||
const { theme } = useUnistyles();
|
||||
const showSection = shouldUseDesktopDaemon();
|
||||
const { settings, updateSettings } = useAppSettings();
|
||||
const [daemonStatus, setDaemonStatus] = useState<DesktopDaemonStatus | null>(null);
|
||||
const [daemonVersion, setDaemonVersion] = useState<string | null>(null);
|
||||
const [statusError, setStatusError] = useState<string | null>(null);
|
||||
const [isRestartingDaemon, setIsRestartingDaemon] = useState(false);
|
||||
const [isUpdatingDaemonManagement, setIsUpdatingDaemonManagement] = useState(false);
|
||||
const [isLoadingCliSymlinkInstructions, setIsLoadingCliSymlinkInstructions] = useState(false);
|
||||
const [statusMessage, setStatusMessage] = useState<string | null>(null);
|
||||
const [cliStatusMessage, setCliStatusMessage] = useState<string | null>(null);
|
||||
const [daemonLogs, setDaemonLogs] = useState<DesktopDaemonLogs | null>(null);
|
||||
const [isLogsModalOpen, setIsLogsModalOpen] = useState(false);
|
||||
const [isPairingModalOpen, setIsPairingModalOpen] = useState(false);
|
||||
const [isCliSymlinkModalOpen, setIsCliSymlinkModalOpen] = useState(false);
|
||||
const [isLoadingPairing, setIsLoadingPairing] = useState(false);
|
||||
const [pairingOffer, setPairingOffer] = useState<DesktopPairingOffer | null>(null);
|
||||
const [cliSymlinkInstructions, setCliSymlinkInstructions] =
|
||||
useState<CliSymlinkInstructions | null>(null)
|
||||
const [pairingStatusMessage, setPairingStatusMessage] = useState<string | null>(null)
|
||||
useState<CliSymlinkInstructions | null>(null);
|
||||
const [pairingStatusMessage, setPairingStatusMessage] = useState<string | null>(null);
|
||||
|
||||
const loadDaemonData = useCallback(() => {
|
||||
if (!showSection) {
|
||||
return Promise.resolve()
|
||||
return Promise.resolve();
|
||||
}
|
||||
return Promise.all([getDesktopDaemonStatus(), getDesktopDaemonLogs(), getLocalDaemonVersion()])
|
||||
.then(([status, logs, version]) => {
|
||||
setDaemonStatus(status)
|
||||
setDaemonLogs(logs)
|
||||
setDaemonVersion(version.version)
|
||||
setStatusError(null)
|
||||
setDaemonStatus(status);
|
||||
setDaemonLogs(logs);
|
||||
setDaemonVersion(version.version);
|
||||
setStatusError(null);
|
||||
})
|
||||
.catch((error) => {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
setStatusError(message)
|
||||
})
|
||||
}, [showSection])
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
setStatusError(message);
|
||||
});
|
||||
}, [showSection]);
|
||||
|
||||
useFocusEffect(
|
||||
useCallback(() => {
|
||||
if (!showSection) {
|
||||
return undefined
|
||||
return undefined;
|
||||
}
|
||||
void loadDaemonData()
|
||||
return undefined
|
||||
}, [loadDaemonData, showSection])
|
||||
)
|
||||
void loadDaemonData();
|
||||
return undefined;
|
||||
}, [loadDaemonData, showSection]),
|
||||
);
|
||||
|
||||
const daemonVersionMismatch = isVersionMismatch(appVersion, daemonVersion)
|
||||
const daemonVersionMismatch = isVersionMismatch(appVersion, daemonVersion);
|
||||
const daemonStatusStateText =
|
||||
statusError ?? (daemonStatus?.status === 'running' ? daemonStatus.status : 'not running')
|
||||
const daemonStatusDetailText = `PID ${daemonStatus?.pid ? daemonStatus.pid : '—'}`
|
||||
const isDaemonManagementPaused = !settings.manageBuiltInDaemon
|
||||
const daemonActionLabel = daemonStatus?.status === 'running' ? 'Restart daemon' : 'Start daemon'
|
||||
statusError ?? (daemonStatus?.status === "running" ? daemonStatus.status : "not running");
|
||||
const daemonStatusDetailText = `PID ${daemonStatus?.pid ? daemonStatus.pid : "—"}`;
|
||||
const isDaemonManagementPaused = !settings.manageBuiltInDaemon;
|
||||
const daemonActionLabel = daemonStatus?.status === "running" ? "Restart daemon" : "Start daemon";
|
||||
const daemonActionMessage =
|
||||
daemonStatus?.status === 'running'
|
||||
? 'Restarts the built-in daemon.'
|
||||
: 'Starts the built-in daemon.'
|
||||
daemonStatus?.status === "running"
|
||||
? "Restarts the built-in daemon."
|
||||
: "Starts the built-in daemon.";
|
||||
|
||||
const handleUpdateLocalDaemon = useCallback(() => {
|
||||
if (!showSection || isRestartingDaemon) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
void confirmDialog({
|
||||
title: daemonActionLabel,
|
||||
message:
|
||||
daemonStatus?.status === 'running'
|
||||
? 'This will restart the built-in daemon. The app will reconnect automatically.'
|
||||
: 'This will start the built-in daemon.',
|
||||
daemonStatus?.status === "running"
|
||||
? "This will restart the built-in daemon. The app will reconnect automatically."
|
||||
: "This will start the built-in daemon.",
|
||||
confirmLabel: daemonActionLabel,
|
||||
cancelLabel: 'Cancel',
|
||||
cancelLabel: "Cancel",
|
||||
})
|
||||
.then((confirmed) => {
|
||||
if (!confirmed) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setIsRestartingDaemon(true)
|
||||
setStatusMessage(null)
|
||||
setIsRestartingDaemon(true);
|
||||
setStatusMessage(null);
|
||||
|
||||
const action = daemonStatus?.status === 'running' ? restartDesktopDaemon : startDesktopDaemon
|
||||
const action =
|
||||
daemonStatus?.status === "running" ? restartDesktopDaemon : startDesktopDaemon;
|
||||
|
||||
void action()
|
||||
.then((status) => {
|
||||
setDaemonStatus(status)
|
||||
setDaemonStatus(status);
|
||||
setStatusMessage(
|
||||
daemonStatus?.status === 'running' ? 'Daemon restarted.' : 'Daemon started.'
|
||||
)
|
||||
return loadDaemonData()
|
||||
daemonStatus?.status === "running" ? "Daemon restarted." : "Daemon started.",
|
||||
);
|
||||
return loadDaemonData();
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to change desktop daemon state', error)
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
setStatusMessage(`${daemonActionLabel} failed: ${message}`)
|
||||
console.error("[Settings] Failed to change desktop daemon state", error);
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
setStatusMessage(`${daemonActionLabel} failed: ${message}`);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsRestartingDaemon(false)
|
||||
})
|
||||
setIsRestartingDaemon(false);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to open desktop daemon action confirmation', error)
|
||||
Alert.alert('Error', 'Unable to open the daemon confirmation dialog.')
|
||||
})
|
||||
}, [daemonActionLabel, daemonStatus?.status, isRestartingDaemon, loadDaemonData, showSection])
|
||||
console.error("[Settings] Failed to open desktop daemon action confirmation", error);
|
||||
Alert.alert("Error", "Unable to open the daemon confirmation dialog.");
|
||||
});
|
||||
}, [daemonActionLabel, daemonStatus?.status, isRestartingDaemon, loadDaemonData, showSection]);
|
||||
|
||||
const handleToggleDaemonManagement = useCallback(() => {
|
||||
if (isUpdatingDaemonManagement) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
if (!settings.manageBuiltInDaemon) {
|
||||
setIsUpdatingDaemonManagement(true)
|
||||
setStatusMessage(null)
|
||||
setIsUpdatingDaemonManagement(true);
|
||||
setStatusMessage(null);
|
||||
void updateSettings({ manageBuiltInDaemon: true })
|
||||
.then(() => {
|
||||
setStatusMessage('Built-in daemon management resumed.')
|
||||
setStatusMessage("Built-in daemon management resumed.");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to update built-in daemon management', error)
|
||||
Alert.alert('Error', 'Unable to update built-in daemon management.')
|
||||
console.error("[Settings] Failed to update built-in daemon management", error);
|
||||
Alert.alert("Error", "Unable to update built-in daemon management.");
|
||||
})
|
||||
.finally(() => {
|
||||
setIsUpdatingDaemonManagement(false)
|
||||
})
|
||||
return
|
||||
setIsUpdatingDaemonManagement(false);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
void confirmDialog({
|
||||
title: 'Pause built-in daemon',
|
||||
title: "Pause built-in daemon",
|
||||
message:
|
||||
'This will stop the built-in daemon immediately. Running agents and terminals connected to the built-in daemon will be stopped.',
|
||||
confirmLabel: 'Pause and stop',
|
||||
cancelLabel: 'Cancel',
|
||||
"This will stop the built-in daemon immediately. Running agents and terminals connected to the built-in daemon will be stopped.",
|
||||
confirmLabel: "Pause and stop",
|
||||
cancelLabel: "Cancel",
|
||||
destructive: true,
|
||||
})
|
||||
.then((confirmed) => {
|
||||
if (!confirmed) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setIsUpdatingDaemonManagement(true)
|
||||
setStatusMessage(null)
|
||||
setIsUpdatingDaemonManagement(true);
|
||||
setStatusMessage(null);
|
||||
|
||||
const stopPromise =
|
||||
daemonStatus?.status === 'running'
|
||||
daemonStatus?.status === "running"
|
||||
? stopDesktopDaemon()
|
||||
: Promise.resolve(daemonStatus ?? null)
|
||||
: Promise.resolve(daemonStatus ?? null);
|
||||
|
||||
void stopPromise
|
||||
.then(() => updateSettings({ manageBuiltInDaemon: false }))
|
||||
.then(() => loadDaemonData())
|
||||
.then(() => {
|
||||
setStatusMessage('Built-in daemon paused and stopped.')
|
||||
setStatusMessage("Built-in daemon paused and stopped.");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to pause built-in daemon management', error)
|
||||
Alert.alert('Error', 'Unable to pause built-in daemon management.')
|
||||
console.error("[Settings] Failed to pause built-in daemon management", error);
|
||||
Alert.alert("Error", "Unable to pause built-in daemon management.");
|
||||
})
|
||||
.finally(() => {
|
||||
setIsUpdatingDaemonManagement(false)
|
||||
})
|
||||
setIsUpdatingDaemonManagement(false);
|
||||
});
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to open built-in daemon pause confirmation', error)
|
||||
Alert.alert('Error', 'Unable to open the daemon confirmation dialog.')
|
||||
})
|
||||
console.error("[Settings] Failed to open built-in daemon pause confirmation", error);
|
||||
Alert.alert("Error", "Unable to open the daemon confirmation dialog.");
|
||||
});
|
||||
}, [
|
||||
daemonStatus,
|
||||
isUpdatingDaemonManagement,
|
||||
loadDaemonData,
|
||||
settings.manageBuiltInDaemon,
|
||||
updateSettings,
|
||||
])
|
||||
]);
|
||||
|
||||
const handleOpenCliSymlinkInstructions = useCallback(() => {
|
||||
if (!showSection || isLoadingCliSymlinkInstructions) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
setIsLoadingCliSymlinkInstructions(true)
|
||||
setCliStatusMessage(null)
|
||||
setIsLoadingCliSymlinkInstructions(true);
|
||||
setCliStatusMessage(null);
|
||||
void getCliSymlinkInstructions()
|
||||
.then((instructions) => {
|
||||
setCliSymlinkInstructions(instructions)
|
||||
setIsCliSymlinkModalOpen(true)
|
||||
setCliSymlinkInstructions(instructions);
|
||||
setIsCliSymlinkModalOpen(true);
|
||||
})
|
||||
.catch((error) => {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
setCliStatusMessage(`Unable to load CLI symlink instructions: ${message}`)
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
setCliStatusMessage(`Unable to load CLI symlink instructions: ${message}`);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoadingCliSymlinkInstructions(false)
|
||||
})
|
||||
}, [isLoadingCliSymlinkInstructions, showSection])
|
||||
setIsLoadingCliSymlinkInstructions(false);
|
||||
});
|
||||
}, [isLoadingCliSymlinkInstructions, showSection]);
|
||||
|
||||
const handleCopyCliSymlinkCommands = useCallback(() => {
|
||||
if (!cliSymlinkInstructions?.commands) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
void Clipboard.setStringAsync(cliSymlinkInstructions.commands)
|
||||
.then(() => {
|
||||
Alert.alert('Copied', 'CLI symlink commands copied.')
|
||||
Alert.alert("Copied", "CLI symlink commands copied.");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to copy CLI symlink commands', error)
|
||||
Alert.alert('Error', 'Unable to copy CLI symlink commands.')
|
||||
})
|
||||
}, [cliSymlinkInstructions?.commands])
|
||||
console.error("[Settings] Failed to copy CLI symlink commands", error);
|
||||
Alert.alert("Error", "Unable to copy CLI symlink commands.");
|
||||
});
|
||||
}, [cliSymlinkInstructions?.commands]);
|
||||
|
||||
const handleCopyLogPath = useCallback(() => {
|
||||
const logPath = daemonLogs?.logPath
|
||||
const logPath = daemonLogs?.logPath;
|
||||
if (!logPath) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
void Clipboard.setStringAsync(logPath)
|
||||
.then(() => {
|
||||
Alert.alert('Copied', 'Log path copied.')
|
||||
Alert.alert("Copied", "Log path copied.");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to copy log path', error)
|
||||
Alert.alert('Error', 'Unable to copy log path.')
|
||||
})
|
||||
}, [daemonLogs?.logPath])
|
||||
console.error("[Settings] Failed to copy log path", error);
|
||||
Alert.alert("Error", "Unable to copy log path.");
|
||||
});
|
||||
}, [daemonLogs?.logPath]);
|
||||
|
||||
const handleOpenLogs = useCallback(() => {
|
||||
if (!daemonLogs) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
setIsLogsModalOpen(true)
|
||||
}, [daemonLogs])
|
||||
setIsLogsModalOpen(true);
|
||||
}, [daemonLogs]);
|
||||
|
||||
const handleOpenPairingModal = useCallback(() => {
|
||||
if (isLoadingPairing) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
|
||||
setIsPairingModalOpen(true)
|
||||
setIsLoadingPairing(true)
|
||||
setPairingStatusMessage(null)
|
||||
setIsPairingModalOpen(true);
|
||||
setIsLoadingPairing(true);
|
||||
setPairingStatusMessage(null);
|
||||
|
||||
void getDesktopDaemonPairing()
|
||||
.then((pairing) => {
|
||||
setPairingOffer(pairing)
|
||||
setPairingOffer(pairing);
|
||||
if (!pairing.relayEnabled || !pairing.url) {
|
||||
setPairingStatusMessage('Relay pairing is not available.')
|
||||
setPairingStatusMessage("Relay pairing is not available.");
|
||||
}
|
||||
})
|
||||
.catch((error) => {
|
||||
const message = error instanceof Error ? error.message : String(error)
|
||||
setPairingOffer(null)
|
||||
setPairingStatusMessage(`Unable to load pairing offer: ${message}`)
|
||||
const message = error instanceof Error ? error.message : String(error);
|
||||
setPairingOffer(null);
|
||||
setPairingStatusMessage(`Unable to load pairing offer: ${message}`);
|
||||
})
|
||||
.finally(() => {
|
||||
setIsLoadingPairing(false)
|
||||
})
|
||||
}, [isLoadingPairing])
|
||||
setIsLoadingPairing(false);
|
||||
});
|
||||
}, [isLoadingPairing]);
|
||||
|
||||
const handleCopyPairingLink = useCallback(() => {
|
||||
if (!pairingOffer?.url) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
void Clipboard.setStringAsync(pairingOffer.url)
|
||||
.then(() => {
|
||||
Alert.alert('Copied', 'Pairing link copied.')
|
||||
Alert.alert("Copied", "Pairing link copied.");
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('[Settings] Failed to copy pairing link', error)
|
||||
Alert.alert('Error', 'Unable to copy pairing link.')
|
||||
})
|
||||
}, [pairingOffer?.url])
|
||||
console.error("[Settings] Failed to copy pairing link", error);
|
||||
Alert.alert("Error", "Unable to copy pairing link.");
|
||||
});
|
||||
}, [pairingOffer?.url]);
|
||||
|
||||
if (!showSection) {
|
||||
return null
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -355,8 +353,8 @@ export function LocalDaemonSection({
|
||||
<Text style={styles.rowTitle}>Daemon management</Text>
|
||||
<Text style={styles.hintText}>
|
||||
{isDaemonManagementPaused
|
||||
? 'Paused. The built-in daemon stays stopped until you start it again.'
|
||||
: 'Enabled. Paseo can manage the built-in daemon from the desktop app.'}
|
||||
? "Paused. The built-in daemon stays stopped until you start it again."
|
||||
: "Enabled. Paseo can manage the built-in daemon from the desktop app."}
|
||||
</Text>
|
||||
</View>
|
||||
<Button
|
||||
@@ -374,11 +372,11 @@ export function LocalDaemonSection({
|
||||
>
|
||||
{isUpdatingDaemonManagement
|
||||
? isDaemonManagementPaused
|
||||
? 'Resuming...'
|
||||
: 'Pausing...'
|
||||
? "Resuming..."
|
||||
: "Pausing..."
|
||||
: isDaemonManagementPaused
|
||||
? 'Resume'
|
||||
: 'Pause'}
|
||||
? "Resume"
|
||||
: "Pause"}
|
||||
</Button>
|
||||
</View>
|
||||
<View style={[styles.row, styles.rowBorder]}>
|
||||
@@ -395,9 +393,9 @@ export function LocalDaemonSection({
|
||||
disabled={isRestartingDaemon}
|
||||
>
|
||||
{isRestartingDaemon
|
||||
? daemonStatus?.status === 'running'
|
||||
? 'Restarting...'
|
||||
: 'Starting...'
|
||||
? daemonStatus?.status === "running"
|
||||
? "Restarting..."
|
||||
: "Starting..."
|
||||
: daemonActionLabel}
|
||||
</Button>
|
||||
</View>
|
||||
@@ -416,13 +414,13 @@ export function LocalDaemonSection({
|
||||
onPress={handleOpenCliSymlinkInstructions}
|
||||
disabled={isLoadingCliSymlinkInstructions}
|
||||
>
|
||||
{isLoadingCliSymlinkInstructions ? 'Loading...' : 'Show instructions'}
|
||||
{isLoadingCliSymlinkInstructions ? "Loading..." : "Show instructions"}
|
||||
</Button>
|
||||
</View>
|
||||
<View style={[styles.row, styles.rowBorder]}>
|
||||
<View style={styles.rowContent}>
|
||||
<Text style={styles.rowTitle}>Log file</Text>
|
||||
<Text style={styles.hintText}>{daemonLogs?.logPath ?? 'Log path unavailable.'}</Text>
|
||||
<Text style={styles.hintText}>{daemonLogs?.logPath ?? "Log path unavailable."}</Text>
|
||||
</View>
|
||||
<View style={styles.actionGroup}>
|
||||
{daemonLogs?.logPath ? (
|
||||
@@ -485,7 +483,7 @@ export function LocalDaemonSection({
|
||||
<Text style={styles.hintText}>{cliSymlinkInstructions.detail}</Text>
|
||||
) : null}
|
||||
<Text style={styles.codeBlock} selectable>
|
||||
{cliSymlinkInstructions?.commands ?? ''}
|
||||
{cliSymlinkInstructions?.commands ?? ""}
|
||||
</Text>
|
||||
<View style={styles.modalActions}>
|
||||
<Button variant="outline" size="sm" onPress={() => setIsCliSymlinkModalOpen(false)}>
|
||||
@@ -517,67 +515,67 @@ export function LocalDaemonSection({
|
||||
onClose={() => setIsLogsModalOpen(false)}
|
||||
title="Daemon logs"
|
||||
testID="managed-daemon-logs-dialog"
|
||||
snapPoints={['70%', '92%']}
|
||||
snapPoints={["70%", "92%"]}
|
||||
>
|
||||
<View style={styles.modalBody}>
|
||||
<Text style={styles.hintText}>{daemonLogs?.logPath ?? 'Log path unavailable.'}</Text>
|
||||
<Text style={styles.hintText}>{daemonLogs?.logPath ?? "Log path unavailable."}</Text>
|
||||
<Text style={styles.logOutput} selectable>
|
||||
{daemonLogs?.contents.length ? daemonLogs.contents : '(log file is empty)'}
|
||||
{daemonLogs?.contents.length ? daemonLogs.contents : "(log file is empty)"}
|
||||
</Text>
|
||||
</View>
|
||||
</AdaptiveModalSheet>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const ADVANCED_DAEMON_SETTINGS_URL = 'https://paseo.sh/docs/configuration'
|
||||
const ADVANCED_DAEMON_SETTINGS_URL = "https://paseo.sh/docs/configuration";
|
||||
|
||||
function PairingOfferDialogContent(input: {
|
||||
isLoading: boolean
|
||||
pairingOffer: DesktopPairingOffer | null
|
||||
statusMessage: string | null
|
||||
onCopyLink: () => void
|
||||
isLoading: boolean;
|
||||
pairingOffer: DesktopPairingOffer | null;
|
||||
statusMessage: string | null;
|
||||
onCopyLink: () => void;
|
||||
}) {
|
||||
const { isLoading, pairingOffer, statusMessage, onCopyLink } = input
|
||||
const [qrDataUrl, setQrDataUrl] = useState<string | null>(null)
|
||||
const [qrError, setQrError] = useState<string | null>(null)
|
||||
const { isLoading, pairingOffer, statusMessage, onCopyLink } = input;
|
||||
const [qrDataUrl, setQrDataUrl] = useState<string | null>(null);
|
||||
const [qrError, setQrError] = useState<string | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
let cancelled = false
|
||||
let cancelled = false;
|
||||
|
||||
if (!pairingOffer?.url) {
|
||||
setQrDataUrl(null)
|
||||
setQrError(null)
|
||||
setQrDataUrl(null);
|
||||
setQrError(null);
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
cancelled = true;
|
||||
};
|
||||
}
|
||||
|
||||
setQrError(null)
|
||||
setQrDataUrl(null)
|
||||
setQrError(null);
|
||||
setQrDataUrl(null);
|
||||
|
||||
void QRCode.toDataURL(pairingOffer.url, {
|
||||
errorCorrectionLevel: 'M',
|
||||
errorCorrectionLevel: "M",
|
||||
margin: 1,
|
||||
width: 480,
|
||||
})
|
||||
.then((dataUrl) => {
|
||||
if (cancelled) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
setQrDataUrl(dataUrl)
|
||||
setQrDataUrl(dataUrl);
|
||||
})
|
||||
.catch((error) => {
|
||||
if (cancelled) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
setQrError(error instanceof Error ? error.message : String(error))
|
||||
})
|
||||
setQrError(error instanceof Error ? error.message : String(error));
|
||||
});
|
||||
|
||||
return () => {
|
||||
cancelled = true
|
||||
}
|
||||
}, [pairingOffer?.url])
|
||||
cancelled = true;
|
||||
};
|
||||
}, [pairingOffer?.url]);
|
||||
|
||||
if (isLoading) {
|
||||
return (
|
||||
@@ -585,7 +583,7 @@ function PairingOfferDialogContent(input: {
|
||||
<ActivityIndicator size="small" />
|
||||
<Text style={styles.hintText}>Loading pairing offer…</Text>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (statusMessage) {
|
||||
@@ -593,7 +591,7 @@ function PairingOfferDialogContent(input: {
|
||||
<View style={styles.modalBody}>
|
||||
<Text style={styles.hintText}>{statusMessage}</Text>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (!pairingOffer?.url) {
|
||||
@@ -601,7 +599,7 @@ function PairingOfferDialogContent(input: {
|
||||
<View style={styles.modalBody}>
|
||||
<Text style={styles.hintText}>Pairing offer unavailable.</Text>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
@@ -630,20 +628,20 @@ function PairingOfferDialogContent(input: {
|
||||
</Button>
|
||||
</View>
|
||||
</View>
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create((theme) => ({
|
||||
sectionHeader: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
justifyContent: "space-between",
|
||||
marginBottom: theme.spacing[3],
|
||||
marginLeft: theme.spacing[1],
|
||||
},
|
||||
sectionLink: {
|
||||
alignItems: 'center',
|
||||
flexDirection: 'row',
|
||||
alignItems: "center",
|
||||
flexDirection: "row",
|
||||
gap: theme.spacing[1],
|
||||
},
|
||||
sectionLinkText: {
|
||||
@@ -651,9 +649,9 @@ const styles = StyleSheet.create((theme) => ({
|
||||
fontSize: theme.fontSize.xs,
|
||||
},
|
||||
row: {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'space-between',
|
||||
flexDirection: "row",
|
||||
alignItems: "center",
|
||||
justifyContent: "space-between",
|
||||
paddingVertical: theme.spacing[4],
|
||||
paddingHorizontal: theme.spacing[4],
|
||||
},
|
||||
@@ -666,13 +664,13 @@ const styles = StyleSheet.create((theme) => ({
|
||||
marginRight: theme.spacing[3],
|
||||
},
|
||||
actionGroup: {
|
||||
flexDirection: 'row',
|
||||
flexDirection: "row",
|
||||
gap: theme.spacing[2],
|
||||
flexWrap: 'wrap',
|
||||
justifyContent: 'flex-end',
|
||||
flexWrap: "wrap",
|
||||
justifyContent: "flex-end",
|
||||
},
|
||||
statusValueGroup: {
|
||||
alignItems: 'flex-end',
|
||||
alignItems: "flex-end",
|
||||
gap: 2,
|
||||
},
|
||||
rowTitle: {
|
||||
@@ -703,7 +701,7 @@ const styles = StyleSheet.create((theme) => ({
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.palette.amber[500],
|
||||
backgroundColor: 'rgba(245, 158, 11, 0.12)',
|
||||
backgroundColor: "rgba(245, 158, 11, 0.12)",
|
||||
paddingVertical: theme.spacing[2],
|
||||
paddingHorizontal: theme.spacing[3],
|
||||
},
|
||||
@@ -716,17 +714,17 @@ const styles = StyleSheet.create((theme) => ({
|
||||
paddingBottom: theme.spacing[2],
|
||||
},
|
||||
pairingState: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
gap: theme.spacing[3],
|
||||
paddingVertical: theme.spacing[6],
|
||||
},
|
||||
qrCard: {
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
width: '100%',
|
||||
alignItems: "center",
|
||||
justifyContent: "center",
|
||||
width: "100%",
|
||||
aspectRatio: 1,
|
||||
alignSelf: 'stretch',
|
||||
alignSelf: "stretch",
|
||||
padding: theme.spacing[3],
|
||||
borderRadius: theme.borderRadius.lg,
|
||||
borderWidth: 1,
|
||||
@@ -734,8 +732,8 @@ const styles = StyleSheet.create((theme) => ({
|
||||
backgroundColor: theme.colors.surface0,
|
||||
},
|
||||
qrImage: {
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
width: "100%",
|
||||
height: "100%",
|
||||
},
|
||||
linkSection: {
|
||||
gap: theme.spacing[2],
|
||||
@@ -752,13 +750,13 @@ const styles = StyleSheet.create((theme) => ({
|
||||
logOutput: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
||||
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
||||
lineHeight: 18,
|
||||
},
|
||||
codeBlock: {
|
||||
color: theme.colors.foregroundMuted,
|
||||
fontSize: theme.fontSize.xs,
|
||||
fontFamily: 'ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace',
|
||||
fontFamily: "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace",
|
||||
lineHeight: 18,
|
||||
borderWidth: 1,
|
||||
borderColor: theme.colors.border,
|
||||
@@ -767,8 +765,8 @@ const styles = StyleSheet.create((theme) => ({
|
||||
padding: theme.spacing[3],
|
||||
},
|
||||
modalActions: {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
flexDirection: "row",
|
||||
justifyContent: "flex-end",
|
||||
gap: theme.spacing[2],
|
||||
},
|
||||
}))
|
||||
}));
|
||||
|
||||
Reference in New Issue
Block a user