diff --git a/packages/app/src/components/provider-diagnostic-sheet.tsx b/packages/app/src/components/provider-diagnostic-sheet.tsx index 6aefebf19..bb2c2b411 100644 --- a/packages/app/src/components/provider-diagnostic-sheet.tsx +++ b/packages/app/src/components/provider-diagnostic-sheet.tsx @@ -1,4 +1,4 @@ -import { AlertCircle, Plus, RotateCw, Search, Trash2 } from "lucide-react-native"; +import { AlertCircle, RotateCw, Search, Trash2 } from "lucide-react-native"; import { useCallback, useEffect, useMemo, useState } from "react"; import { ActivityIndicator, @@ -10,12 +10,15 @@ import { } from "react-native"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { AdaptiveModalSheet, AdaptiveTextInput } from "@/components/adaptive-modal-sheet"; +import { Button } from "@/components/ui/button"; import { LoadingSpinner } from "@/components/ui/loading-spinner"; import { isWeb } from "@/constants/platform"; import { Fonts } from "@/constants/theme"; import { useDaemonConfig } from "@/hooks/use-daemon-config"; import { useProvidersSnapshot } from "@/hooks/use-providers-snapshot"; import { useHostRuntimeClient } from "@/runtime/host-runtime"; +import { SettingsSection } from "@/screens/settings/settings-section"; +import { settingsStyles } from "@/styles/settings"; import { resolveProviderLabel } from "@/utils/provider-definitions"; import { formatTimeAgo } from "@/utils/time"; import type { AgentModelDefinition, AgentProvider } from "@server/server/agent/agent-sdk-types"; @@ -28,35 +31,28 @@ interface ProviderDiagnosticSheetProps { serverId: string; } -function ModelRow({ model, isFirst }: { model: AgentModelDefinition; isFirst: boolean }) { - const rowStyle = useMemo( - () => [sheetStyles.modelRow, !isFirst && sheetStyles.modelRowBorder], - [isFirst], - ); +function ModelRow({ model }: { model: AgentModelDefinition }) { return ( - - - {model.label} - - - {model.id} - + + + + {model.label} + + + {model.id} + + ); } -function AdditionalModelRow(props: { +function CustomModelRow(props: { model: ProviderProfileModel; - isFirst: boolean; deleting: boolean; onDelete: (modelId: string) => void; }) { const { theme } = useUnistyles(); - const { model, isFirst, deleting, onDelete } = props; - const rowStyle = useMemo( - () => [sheetStyles.additionalModelRow, !isFirst && sheetStyles.modelRowBorder], - [isFirst], - ); + const { model, deleting, onDelete } = props; const handleDelete = useCallback(() => onDelete(model.id), [model.id, onDelete]); const deleteButtonStyle = useCallback( ({ hovered, pressed }: PressableStateCallbackType & { hovered?: boolean }) => [ @@ -68,12 +64,12 @@ function AdditionalModelRow(props: { ); return ( - - - + + + {model.label} - + {model.id} @@ -91,7 +87,7 @@ function AdditionalModelRow(props: { ); } -function AdditionalModelsEditor(props: { +function CustomModelsSection(props: { provider: string; serverId: string; refresh: (providers?: AgentProvider[]) => Promise; @@ -162,20 +158,10 @@ function AdditionalModelsEditor(props: { [additionalModels, patchAdditionalModels], ); - const addButtonStyle = useCallback( - ({ hovered, pressed }: PressableStateCallbackType & { hovered?: boolean }) => [ - sheetStyles.addModelButton, - (Boolean(hovered) || pressed) && sheetStyles.addModelButtonHovered, - !canAdd || saving ? sheetStyles.disabled : null, - ], - [canAdd, saving], - ); - return ( - - Additional Models - - + + + + - - {saving ? ( - - ) : ( - - )} - + {additionalModels.map((model) => ( + + ))} {error ? {error} : null} - {additionalModels.length > 0 ? ( - - {additionalModels.map((model, index) => ( - - ))} - - ) : null} - + ); } @@ -251,7 +228,7 @@ function DiagnosticCodeBlock(props: { } return ( - No diagnostic available. + No diagnostic available ); } @@ -288,7 +265,6 @@ export function ProviderDiagnosticSheet({ }, [visible]); const fetchedAtLabel = useMemo(() => { if (!providerEntry?.fetchedAt) return null; - // clockTick is referenced so the label recomputes each timer tick. void clockTick; return formatTimeAgo(new Date(providerEntry.fetchedAt)); }, [providerEntry?.fetchedAt, clockTick]); @@ -375,10 +351,27 @@ export function ProviderDiagnosticSheet({ } }, [visible, fetchDiagnostic]); + const modelsTrailing = useMemo(() => { + if (models.length === 0 && !fetchedAtLabel) return undefined; + return ( + + {models.length > 0 ? ( + {models.length} + ) : null} + {models.length > 0 && fetchedAtLabel ? ( + · + ) : null} + {fetchedAtLabel ? ( + Updated {fetchedAtLabel} + ) : null} + + ); + }, [models.length, fetchedAtLabel]); + function renderModelsBody() { if (models.length === 0 && providerSnapshotRefreshing) { return ( - + Loading models… @@ -386,7 +379,7 @@ export function ProviderDiagnosticSheet({ } if (models.length === 0 && providerErrorMessage) { return ( - + {providerErrorMessage} @@ -394,21 +387,21 @@ export function ProviderDiagnosticSheet({ } if (models.length === 0) { return ( - - No models detected. + + No models detected ); } if (filteredModels.length === 0) { return ( - + No models match your search ); } - return filteredModels.map((model: AgentModelDefinition, index) => ( - + return filteredModels.map((model: AgentModelDefinition) => ( + )); } @@ -421,35 +414,26 @@ export function ProviderDiagnosticSheet({ scrollable={false} headerActions={headerActions} > - - Diagnostic - + + - + + + - - - Models - - {models.length} - {fetchedAtLabel ? ( - <> - · - Updated {fetchedAtLabel} - - ) : null} - + Models + {modelsTrailing} - {models.length > 0 ? ( - - + + + - ) : null} - - {renderModelsBody()} - + + {renderModelsBody()} + + ); } const sheetStyles = StyleSheet.create((theme) => ({ - section: { - gap: theme.spacing[2], - }, - sectionTitle: { - color: theme.colors.foregroundMuted, - fontSize: theme.fontSize.xs, - fontWeight: theme.fontWeight.normal, - }, mutedText: { fontSize: theme.fontSize.sm, color: theme.colors.foregroundMuted, }, + monoHint: { + fontFamily: Fonts.mono, + fontSize: theme.fontSize.xs, + color: theme.colors.foregroundMuted, + marginTop: theme.spacing[1], + }, errorText: { fontSize: theme.fontSize.xs, color: theme.colors.destructive, + marginTop: theme.spacing[2], + marginLeft: theme.spacing[1], }, iconButton: { width: 30, @@ -505,20 +489,24 @@ const sheetStyles = StyleSheet.create((theme) => ({ disabled: { opacity: 0.5, }, - codeBlock: { - borderWidth: 1, - borderColor: theme.colors.border, - borderRadius: theme.borderRadius.base, - backgroundColor: theme.colors.surface2, - overflow: "hidden", - maxHeight: 180, + inlineRow: { + flexDirection: "row", + alignItems: "center", + gap: theme.spacing[2], + }, + inlineInput: { + flex: 1, + minWidth: 0, + paddingVertical: 0, + color: theme.colors.foreground, + fontSize: theme.fontSize.sm, }, codeScroll: { - maxHeight: 180, + maxHeight: 200, }, codeContent: { paddingVertical: theme.spacing[3], - paddingHorizontal: theme.spacing[3], + paddingHorizontal: theme.spacing[4], }, codeText: { fontFamily: Fonts.mono, @@ -528,7 +516,7 @@ const sheetStyles = StyleSheet.create((theme) => ({ }, codeBlockLoading: { paddingVertical: theme.spacing[4], - paddingHorizontal: theme.spacing[3], + paddingHorizontal: theme.spacing[4], flexDirection: "row", alignItems: "center", gap: theme.spacing[2], @@ -536,118 +524,46 @@ const sheetStyles = StyleSheet.create((theme) => ({ modelsSection: { flex: 1, minHeight: 0, - gap: theme.spacing[2], }, modelsHeader: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", + gap: theme.spacing[2], + marginBottom: theme.spacing[3], + marginLeft: theme.spacing[1], }, - modelsHeaderMeta: { + flexCard: { + flex: 1, + minHeight: 0, + }, + modelsTrailing: { flexDirection: "row", alignItems: "center", gap: theme.spacing[1], }, - metaDot: { - fontSize: theme.fontSize.xs, - color: theme.colors.foregroundMuted, - }, - countText: { - fontSize: theme.fontSize.xs, - color: theme.colors.foregroundMuted, - }, - searchContainer: { - flexDirection: "row", - alignItems: "center", - gap: theme.spacing[2], - backgroundColor: theme.colors.surface2, - borderRadius: theme.borderRadius.md, - paddingHorizontal: theme.spacing[3], - }, - addModelRow: { - flexDirection: "row", - alignItems: "center", - gap: theme.spacing[2], - }, - addModelInputContainer: { - flex: 1, - minWidth: 0, - backgroundColor: theme.colors.surface2, - borderRadius: theme.borderRadius.md, - paddingHorizontal: theme.spacing[3], - }, - addModelInput: { - paddingVertical: theme.spacing[2], - color: theme.colors.foreground, - fontSize: theme.fontSize.sm, - }, - addModelButton: { - width: 34, - height: 34, - borderRadius: theme.borderRadius.full, - alignItems: "center", - justifyContent: "center", - backgroundColor: theme.colors.accent, - }, - addModelButtonHovered: { - backgroundColor: theme.colors.accentBright, - }, - additionalModelsList: { - borderTopWidth: 1, - borderTopColor: theme.colors.border, - }, - additionalModelRow: { - minHeight: 48, - paddingVertical: theme.spacing[2], - flexDirection: "row", - alignItems: "center", - justifyContent: "space-between", - gap: theme.spacing[2], - }, - additionalModelText: { - flex: 1, - minWidth: 0, - }, - searchInput: { - flex: 1, - paddingVertical: theme.spacing[2], - color: theme.colors.foreground, - fontSize: theme.fontSize.sm, - }, modelsScroll: { flex: 1, minHeight: 0, }, modelsScrollContent: { - paddingBottom: theme.spacing[2], + paddingBottom: 0, }, - modelRow: { - paddingVertical: theme.spacing[3], - }, - modelRowBorder: { + emptyRow: { + paddingVertical: theme.spacing[6], + paddingHorizontal: theme.spacing[4], + flexDirection: "row", + alignItems: "center", + justifyContent: "center", + gap: theme.spacing[2], borderTopWidth: 1, borderTopColor: theme.colors.border, }, - modelLabel: { - fontSize: theme.fontSize.sm, - color: theme.colors.foreground, - }, - modelId: { - fontSize: theme.fontSize.xs, - color: theme.colors.foregroundMuted, - fontFamily: Fonts.mono, - marginTop: 2, - }, - emptyState: { - paddingVertical: theme.spacing[6], - alignItems: "center", - gap: theme.spacing[2], - }, })); const DIAGNOSTIC_SHEET_SNAP_POINTS = ["50%", "85%"]; -const DIAGNOSTIC_SEARCH_INPUT_STYLE = [sheetStyles.searchInput, isWeb && { outlineStyle: "none" }]; -const DIAGNOSTIC_ADD_MODEL_INPUT_STYLE = [ - sheetStyles.addModelInput, - isWeb && { outlineStyle: "none" }, -]; +const DIAGNOSTIC_SEARCH_INPUT_STYLE = [sheetStyles.inlineInput, isWeb && { outlineStyle: "none" }]; +const DIAGNOSTIC_INLINE_INPUT_STYLE = [sheetStyles.inlineInput, isWeb && { outlineStyle: "none" }]; +const MODEL_ROW_STYLE = [settingsStyles.row, settingsStyles.rowBorder]; +const INLINE_ROW_STYLE = [settingsStyles.row, sheetStyles.inlineRow]; +const MODELS_CARD_STYLE = [settingsStyles.card, sheetStyles.flexCard]; diff --git a/packages/app/src/components/ui/switch.tsx b/packages/app/src/components/ui/switch.tsx index 79ee066dd..66e0738d2 100644 --- a/packages/app/src/components/ui/switch.tsx +++ b/packages/app/src/components/ui/switch.tsx @@ -14,22 +14,17 @@ import Animated, { } from "react-native-reanimated"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; -type SwitchSize = "sm" | "md"; - interface SwitchProps { value: boolean; onValueChange?: (value: boolean) => void; disabled?: boolean; - size?: SwitchSize; accessibilityLabel?: string; testID?: string; style?: StyleProp; } -const SIZES: Record = { - md: { track: { width: 44, height: 26 }, thumb: 22 }, - sm: { track: { width: 34, height: 20 }, thumb: 16 }, -}; +const TRACK = { width: 34, height: 20 }; +const THUMB = 16; const TIMING = { duration: 180, easing: Easing.inOut(Easing.ease) }; @@ -37,13 +32,13 @@ export function Switch({ value, onValueChange, disabled = false, - size = "md", accessibilityLabel, testID, style, }: SwitchProps) { const { theme } = useUnistyles(); - const { track, thumb } = SIZES[size]; + const track = TRACK; + const thumb = THUMB; const padding = (track.height - thumb) / 2; const thumbTravel = track.width - thumb - padding * 2; diff --git a/packages/app/src/desktop/components/desktop-updates-section.test.tsx b/packages/app/src/desktop/components/desktop-updates-section.test.tsx index 1d2c1fe4b..12830a72e 100644 --- a/packages/app/src/desktop/components/desktop-updates-section.test.tsx +++ b/packages/app/src/desktop/components/desktop-updates-section.test.tsx @@ -98,9 +98,6 @@ vi.mock("lucide-react-native", () => { ArrowUpRight: icon("ArrowUpRight"), Copy: icon("Copy"), FileText: icon("FileText"), - Pause: icon("Pause"), - Play: icon("Play"), - RotateCw: icon("RotateCw"), }; }); @@ -163,6 +160,28 @@ vi.mock("@/components/ui/button", () => ({ ), })); +vi.mock("@/components/ui/switch", () => ({ + Switch: ({ + value, + onValueChange, + disabled, + accessibilityLabel, + }: { + value: boolean; + onValueChange?: (next: boolean) => void; + disabled?: boolean; + accessibilityLabel?: string; + }) => + React.createElement("button", { + type: "button", + role: "switch", + "aria-label": accessibilityLabel, + "aria-checked": value, + disabled, + onClick: () => onValueChange?.(!value), + }), +})); + vi.mock("@/desktop/settings/desktop-settings", () => ({ useDesktopSettings: () => ({ ...settingsState, @@ -189,16 +208,12 @@ vi.mock("@/desktop/updates/desktop-updates", () => ({ const daemonCommandMocks = vi.hoisted(() => ({ getCliDaemonStatusMock: vi.fn(), - restartDesktopDaemonMock: vi.fn(), - startDesktopDaemonMock: vi.fn(), stopDesktopDaemonMock: vi.fn(), })); vi.mock("@/desktop/daemon/desktop-daemon", () => ({ getCliDaemonStatus: daemonCommandMocks.getCliDaemonStatusMock, - restartDesktopDaemon: daemonCommandMocks.restartDesktopDaemonMock, shouldUseDesktopDaemon: vi.fn(() => true), - startDesktopDaemon: daemonCommandMocks.startDesktopDaemonMock, stopDesktopDaemon: daemonCommandMocks.stopDesktopDaemonMock, })); @@ -221,32 +236,40 @@ describe("LocalDaemonSection", () => { daemonStatusState.data.status.status = "running"; daemonStatusState.setStatus.mockReset(); daemonStatusState.refetch.mockReset(); - daemonCommandMocks.startDesktopDaemonMock.mockReset(); daemonCommandMocks.stopDesktopDaemonMock.mockReset(); daemonCommandMocks.stopDesktopDaemonMock.mockResolvedValue({ ...daemonStatusState.data.status, status: "stopped", }); - daemonCommandMocks.restartDesktopDaemonMock.mockReset(); daemonCommandMocks.getCliDaemonStatusMock.mockReset(); }); - it("shows the keep-running-after-quit control enabled by default", () => { + it("renders the daemon toggles as switches reflecting current settings", () => { const screen = render(); expect(screen.getByText("Keep daemon running after quit")).toBeTruthy(); - expect( - screen.getByText( - "Enabled. The built-in daemon keeps running after you close the desktop app.", - ), - ).toBeTruthy(); - expect(screen.getByRole("button", { name: "Disable" })).toBeTruthy(); + expect(screen.getByText("Manage built-in daemon")).toBeTruthy(); + + const keepRunningSwitch = screen.getByRole("switch", { + name: "Keep daemon running after quit", + }); + expect(keepRunningSwitch.getAttribute("aria-checked")).toBe("true"); + + const manageSwitch = screen.getByRole("switch", { name: "Manage built-in daemon" }); + expect(manageSwitch.getAttribute("aria-checked")).toBe("true"); + }); + + it("does not render a duplicate restart-daemon control", () => { + const screen = render(); + + expect(screen.queryByText("Restart daemon")).toBeNull(); + expect(screen.queryByText("Start daemon")).toBeNull(); }); it("updates keep-running-after-quit without changing daemon lifecycle", async () => { const screen = render(); - fireEvent.click(screen.getByRole("button", { name: "Disable" })); + fireEvent.click(screen.getByRole("switch", { name: "Keep daemon running after quit" })); await waitFor(() => { expect(settingsState.updateSettings).toHaveBeenCalledWith({ @@ -256,16 +279,14 @@ describe("LocalDaemonSection", () => { }); }); expect(confirmDialogMock).not.toHaveBeenCalled(); - expect(daemonCommandMocks.startDesktopDaemonMock).not.toHaveBeenCalled(); expect(daemonCommandMocks.stopDesktopDaemonMock).not.toHaveBeenCalled(); - expect(daemonCommandMocks.restartDesktopDaemonMock).not.toHaveBeenCalled(); }); it("pauses built-in daemon management and persists the setting through desktop settings", async () => { confirmDialogMock.mockResolvedValue(true); const screen = render(); - fireEvent.click(screen.getByRole("button", { name: "Pause" })); + fireEvent.click(screen.getByRole("switch", { name: "Manage built-in daemon" })); await waitFor(() => { expect(daemonCommandMocks.stopDesktopDaemonMock).toHaveBeenCalledTimes(1); diff --git a/packages/app/src/desktop/components/desktop-updates-section.tsx b/packages/app/src/desktop/components/desktop-updates-section.tsx index 7a08ae0a1..5991afc97 100644 --- a/packages/app/src/desktop/components/desktop-updates-section.tsx +++ b/packages/app/src/desktop/components/desktop-updates-section.tsx @@ -4,17 +4,16 @@ import * as Clipboard from "expo-clipboard"; import { StyleSheet, useUnistyles } from "react-native-unistyles"; import { settingsStyles } from "@/styles/settings"; import { SettingsSection } from "@/screens/settings/settings-section"; -import { ArrowUpRight, Play, Pause, RotateCw, Copy, FileText, Activity } from "lucide-react-native"; +import { ArrowUpRight, Copy, FileText, Activity } from "lucide-react-native"; import { AdaptiveModalSheet } from "@/components/adaptive-modal-sheet"; import { Button } from "@/components/ui/button"; +import { Switch } from "@/components/ui/switch"; import { confirmDialog } from "@/utils/confirm-dialog"; import { openExternalUrl } from "@/utils/open-external-url"; import { isVersionMismatch } from "@/desktop/updates/desktop-updates"; import { getCliDaemonStatus, - restartDesktopDaemon, shouldUseDesktopDaemon, - startDesktopDaemon, stopDesktopDaemon, } from "@/desktop/daemon/desktop-daemon"; import { useDaemonStatus } from "@/desktop/hooks/use-daemon-status"; @@ -24,101 +23,14 @@ import { resolveAppVersion } from "@/utils/app-version"; type DesktopDaemonSettings = DesktopSettings["daemon"]; -function managementLabel(isUpdating: boolean, isPaused: boolean): string { - if (isUpdating) return isPaused ? "Resuming..." : "Pausing..."; - return isPaused ? "Resume" : "Pause"; -} - -function keepRunningLabel(isUpdating: boolean, isEnabled: boolean): string { - if (isUpdating) return isEnabled ? "Disabling..." : "Enabling..."; - return isEnabled ? "Disable" : "Enable"; -} - -function restartLabel(isRestarting: boolean, isRunning: boolean, idleLabel: string): string { - if (!isRestarting) return idleLabel; - return isRunning ? "Restarting..." : "Starting..."; -} - -function useDaemonRestartAction(args: { - showSection: boolean; - daemonStatus: DesktopDaemonStatus | null; - daemonActionLabel: string; - setStatus: (status: DesktopDaemonStatus) => void; - refetch: () => void; -}) { - const { showSection, daemonStatus, daemonActionLabel, setStatus, refetch } = args; - const [isRestartingDaemon, setIsRestartingDaemon] = useState(false); - const [statusMessage, setStatusMessage] = useState(null); - - const handleUpdateLocalDaemon = useCallback(() => { - if (!showSection || isRestartingDaemon) { - 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.", - confirmLabel: daemonActionLabel, - cancelLabel: "Cancel", - }) - .then((confirmed) => { - if (!confirmed) { - return; - } - - setIsRestartingDaemon(true); - setStatusMessage(null); - - const action = - daemonStatus?.status === "running" ? restartDesktopDaemon : startDesktopDaemon; - - void action() - .then((newStatus) => { - setStatus(newStatus); - setStatusMessage( - daemonStatus?.status === "running" ? "Daemon restarted." : "Daemon started.", - ); - refetch(); - return; - }) - .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}`); - }) - .finally(() => { - setIsRestartingDaemon(false); - }); - return; - }) - .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, - refetch, - setStatus, - showSection, - ]); - - return { isRestartingDaemon, statusMessage, setStatusMessage, handleUpdateLocalDaemon }; -} - function useDaemonManagementToggle(args: { daemonStatus: DesktopDaemonStatus | null; settings: DesktopDaemonSettings; updateSettings: (next: Partial) => Promise; setStatus: (status: DesktopDaemonStatus) => void; - setStatusMessage: (message: string | null) => void; refetch: () => void; }) { - const { daemonStatus, settings, updateSettings, setStatus, setStatusMessage, refetch } = args; + const { daemonStatus, settings, updateSettings, setStatus, refetch } = args; const [isUpdatingDaemonManagement, setIsUpdatingDaemonManagement] = useState(false); const handleToggleDaemonManagement = useCallback(() => { @@ -128,12 +40,7 @@ function useDaemonManagementToggle(args: { if (!settings.manageBuiltInDaemon) { setIsUpdatingDaemonManagement(true); - setStatusMessage(null); void updateSettings({ manageBuiltInDaemon: true }) - .then(() => { - setStatusMessage("Built-in daemon management resumed."); - return; - }) .catch((error) => { console.error("[Settings] Failed to update built-in daemon management", error); Alert.alert("Error", "Unable to update built-in daemon management."); @@ -158,7 +65,6 @@ function useDaemonManagementToggle(args: { } setIsUpdatingDaemonManagement(true); - setStatusMessage(null); const stopPromise = daemonStatus?.status === "running" @@ -174,7 +80,6 @@ function useDaemonManagementToggle(args: { }) .then(() => { refetch(); - setStatusMessage("Built-in daemon paused and stopped."); return; }) .catch((error) => { @@ -195,7 +100,6 @@ function useDaemonManagementToggle(args: { isUpdatingDaemonManagement, refetch, setStatus, - setStatusMessage, settings.manageBuiltInDaemon, updateSettings, ]); @@ -318,7 +222,7 @@ function DaemonLogsModal({ visible, onClose, daemonLogs }: DaemonLogsModalProps) snapPoints={LOGS_MODAL_SNAP_POINTS} > - {daemonLogs?.logPath ?? "Log path unavailable."} + {daemonLogs?.logPath ?? "Log path unavailable"} {daemonLogs?.contents?.length ? daemonLogs.contents : "(log file is empty)"} @@ -369,9 +273,6 @@ interface DaemonInfoCardProps { daemonStatusStateText: string; daemonStatusDetailText: string; isDaemonManagementPaused: boolean; - playIcon: ReactElement; - pauseIcon: ReactElement; - rotateIcon: ReactElement; copyIcon: ReactElement; fileTextIcon: ReactElement; activityIcon: ReactElement; @@ -380,12 +281,6 @@ interface DaemonInfoCardProps { keepRunningAfterQuit: boolean; handleToggleKeepRunningAfterQuit: () => void; isUpdatingKeepRunningAfterQuit: boolean; - daemonActionLabel: string; - daemonActionMessage: string; - statusMessage: string | null; - handleUpdateLocalDaemon: () => void; - isRestartingDaemon: boolean; - daemonStatus: DesktopDaemonStatus | null; daemonLogs: { logPath?: string } | null; handleCopyLogPath: () => void; handleOpenLogs: () => void; @@ -398,9 +293,6 @@ function DaemonInfoCard(props: DaemonInfoCardProps) { daemonStatusStateText, daemonStatusDetailText, isDaemonManagementPaused, - playIcon, - pauseIcon, - rotateIcon, copyIcon, fileTextIcon, activityIcon, @@ -409,12 +301,6 @@ function DaemonInfoCard(props: DaemonInfoCardProps) { keepRunningAfterQuit, handleToggleKeepRunningAfterQuit, isUpdatingKeepRunningAfterQuit, - daemonActionLabel, - daemonActionMessage, - statusMessage, - handleUpdateLocalDaemon, - isRestartingDaemon, - daemonStatus, daemonLogs, handleCopyLogPath, handleOpenLogs, @@ -422,28 +308,12 @@ function DaemonInfoCard(props: DaemonInfoCardProps) { isLoadingCliStatus, } = props; - const managementButtonLabel = managementLabel( - isUpdatingDaemonManagement, - isDaemonManagementPaused, - ); - const keepRunningButtonLabel = keepRunningLabel( - isUpdatingKeepRunningAfterQuit, - keepRunningAfterQuit, - ); - const restartButtonLabel = restartLabel( - isRestartingDaemon, - daemonStatus?.status === "running", - daemonActionLabel, - ); - return ( Status - - Only the built-in desktop daemon is shown here. - + Only the built-in desktop daemon is shown here {daemonStatusStateText} @@ -452,62 +322,33 @@ function DaemonInfoCard(props: DaemonInfoCardProps) { - Daemon management - - {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."} - + Manage built-in daemon + Let Paseo start and stop the built-in daemon - + accessibilityLabel="Manage built-in daemon" + /> Keep daemon running after quit - - {keepRunningAfterQuit - ? "Enabled. The built-in daemon keeps running after you close the desktop app." - : "Disabled. Quitting the desktop app stops the built-in daemon if desktop management is enabled."} - + Daemon keeps running when you quit Paseo - - - - - {daemonActionLabel} - {daemonActionMessage} - {statusMessage ? {statusMessage} : null} - - + accessibilityLabel="Keep daemon running after quit" + /> Log file - {daemonLogs?.logPath ?? "Log path unavailable."} + {daemonLogs?.logPath ?? "Log path unavailable"} @@ -531,7 +372,7 @@ function DaemonInfoCard(props: DaemonInfoCardProps) { Full status - Runs `paseo daemon status` and shows the output. + Runs `paseo daemon status` and shows the output