remove the double try/catch cases on the frontend side for cleaner code

This commit is contained in:
Egor 2025-09-18 18:30:21 -07:00
parent 3eb97f5683
commit 0b905a7f67
22 changed files with 250 additions and 364 deletions

View file

@ -12,7 +12,6 @@ import { StatusBar } from '@/components/StatusBar';
import { ErrorBoundary } from '@/components/ErrorBoundary';
import { useUpdateChecker } from '@/hooks/useUpdateChecker';
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
import { safeExecute } from '@/utils/logger';
import { STATUSBAR_HEIGHT, TITLEBAR_HEIGHT } from '@/constants';
import type { DownloadItem } from '@/types/electron';
import type { InterfaceTab, Screen } from '@/types';
@ -40,7 +39,6 @@ export const App = () => {
useEffect(() => {
const checkInstallation = async () => {
await safeExecute(async () => {
const [currentVersion, hasSeenWelcome] = await Promise.all([
window.electronAPI.kobold.getCurrentVersion(),
window.electronAPI.config.get('hasSeenWelcome') as Promise<boolean>,
@ -59,7 +57,6 @@ export const App = () => {
checkForUpdates();
}, 2000);
}
}, 'Error checking installation:');
setHasInitialized(true);
};
@ -69,7 +66,6 @@ export const App = () => {
}, []);
const handleBinaryUpdate = async (download: DownloadItem) => {
await safeExecute(async () => {
const success = await sharedHandleDownload({
item: download,
isUpdate: true,
@ -79,13 +75,10 @@ export const App = () => {
if (success) {
dismissUpdate();
}
}, 'Failed to update binary:');
};
const handleDownloadComplete = async () => {
await safeExecute(async () => {
await window.electronAPI.kobold.getCurrentVersion();
}, 'Error refreshing versions after download:');
setTimeout(() => {
setCurrentScreen('launch');

View file

@ -2,7 +2,6 @@ import { ReactNode } from 'react';
import { Center, Stack, Text, Button, Alert, rem } from '@mantine/core';
import { AlertTriangle, FolderOpen } from 'lucide-react';
import { ErrorBoundary as ReactErrorBoundary } from 'react-error-boundary';
import { safeExecute } from '@/utils/logger';
interface ErrorBoundaryProps {
children: ReactNode;
@ -39,12 +38,7 @@ const ErrorFallback = ({
leftSection={
<FolderOpen style={{ width: rem(16), height: rem(16) }} />
}
onClick={async () => {
await safeExecute(
() => window.electronAPI.app.showLogsFolder(),
'Failed to open logs folder'
);
}}
onClick={() => window.electronAPI.app.showLogsFolder()}
>
Show Logs Folder
</Button>

View file

@ -1,6 +1,5 @@
import { Badge, Tooltip } from '@mantine/core';
import { useState } from 'react';
import { safeExecute } from '@/utils/logger';
interface PerformanceBadgeProps {
label: string;
@ -16,12 +15,9 @@ export const PerformanceBadge = ({
const [isHovered, setIsHovered] = useState(false);
const handlePerformanceClick = async () => {
const result = await safeExecute(
() => window.electronAPI.app.openPerformanceManager(),
'Failed to open performance manager'
);
const result = await window.electronAPI.app.openPerformanceManager();
if (result && !result.success) {
if (!result.success) {
window.electronAPI.logs.logError(
`Failed to open performance manager: ${result.error}`
);

View file

@ -1,11 +1,10 @@
import { useState, useCallback, useEffect, useRef } from 'react';
import { useState, useCallback, useRef, useEffect } from 'react';
import { Card, Text, Title, Loader, Stack, Container } from '@mantine/core';
import { DownloadCard } from '@/components/DownloadCard';
import { getPlatformDisplayName } from '@/utils/platform';
import { formatDownloadSize } from '@/utils/format';
import { getAssetDescription } from '@/utils/assets';
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
import { safeExecute } from '@/utils/logger';
import type { DownloadItem } from '@/types/electron';
interface DownloadScreenProps {
@ -32,7 +31,6 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
async (download: DownloadItem) => {
setDownloadingAsset(download.name);
await safeExecute(async () => {
const success = await sharedHandleDownload({
item: download,
isUpdate: false,
@ -46,7 +44,6 @@ export const DownloadScreen = ({ onDownloadComplete }: DownloadScreenProps) => {
setDownloadingAsset(null);
}, 200);
}
}, `Failed to download ${download.name}:`);
setDownloadingAsset(null);
},

View file

@ -11,7 +11,6 @@ import { InfoTooltip } from '@/components/InfoTooltip';
import { CheckboxWithTooltip } from '@/components/CheckboxWithTooltip';
import { CommandLineArgumentsModal } from '@/components/CommandLineArgumentsModal';
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
import { safeExecute } from '@/utils/logger';
export const AdvancedTab = () => {
const {
@ -56,10 +55,7 @@ export const AdvancedTab = () => {
useEffect(() => {
const detectBackendSupport = async () => {
const support = await safeExecute(
() => window.electronAPI.kobold.detectBackendSupport(),
'Failed to detect backend support:'
);
const support = await window.electronAPI.kobold.detectBackendSupport();
if (support) {
setBackendSupport({

View file

@ -4,7 +4,6 @@ import { InfoTooltip } from '@/components/InfoTooltip';
import { BackendSelectItem } from '@/components/screens/Launch/GeneralTab/BackendSelectItem';
import { GpuDeviceSelector } from '@/components/screens/Launch/GeneralTab/GpuDeviceSelector';
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
import { safeExecute } from '@/utils/logger';
import type { BackendOption } from '@/types';
export const BackendSelector = () => {
@ -26,10 +25,8 @@ export const BackendSelector = () => {
useEffect(() => {
const loadBackends = async () => {
setIsLoadingBackends(true);
const backends = await safeExecute(
() => window.electronAPI.kobold.getAvailableBackends(true),
'Failed to detect available backends:'
);
const backends =
await window.electronAPI.kobold.getAvailableBackends(true);
setAvailableBackends(backends || []);
setIsLoadingBackends(false);
hasInitialized.current = true;

View file

@ -1,6 +1,6 @@
import { Card, Container, Stack, Tabs, Group, Button } from '@mantine/core';
import { useState, useEffect, useCallback, useRef } from 'react';
import { logError, safeExecute } from '@/utils/logger';
import { logError } from '@/utils/logger';
import { useLaunchConfig } from '@/hooks/useLaunchConfig';
import { useLaunchLogic } from '@/hooks/useLaunchLogic';
import { useWarnings } from '@/hooks/useWarnings';
@ -81,10 +81,7 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
});
const setHappyDefaults = useCallback(async () => {
const backends = await safeExecute(
() => window.electronAPI.kobold.getAvailableBackends(),
'Failed to set defaults:'
);
const backends = await window.electronAPI.kobold.getAvailableBackends();
if (!backend && backends && backends.length > 0) {
handleBackendChange(backends[0].value);
@ -183,7 +180,6 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
});
const handleCreateNewConfig = async (configName: string) => {
await safeExecute(async () => {
const fullConfigName = `${configName}.json`;
const saveSuccess = await window.electronAPI.kobold.saveConfigFile(
fullConfigName,
@ -200,7 +196,6 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
new Error('Save operation failed')
);
}
}, 'Failed to create new configuration:');
};
const handleSaveConfig = async () => {
@ -212,7 +207,6 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
return false;
}
const success = await safeExecute(async () => {
const saveSuccess = await window.electronAPI.kobold.saveConfigFile(
selectedFile,
buildConfigData()
@ -227,9 +221,6 @@ export const LaunchScreen = ({ onLaunch }: LaunchScreenProps) => {
}
return true;
}, 'Failed to save configuration:');
return success ?? false;
};
useEffect(() => {

View file

@ -24,10 +24,7 @@ export const AboutTab = () => {
const { handleLogoClick, getLogoStyles } = useLogoClickSounds();
useEffect(() => {
const loadVersionInfo = async () => {
const info = await safeExecute(
() => window.electronAPI.app.getVersionInfo(),
'Failed to load version info'
);
const info = await window.electronAPI.app.getVersionInfo();
if (info) {
setVersionInfo(info);
}
@ -48,9 +45,7 @@ export const AboutTab = () => {
{ label: 'Electron', value: versionInfo.electronVersion },
{
label: 'Node.js',
value:
versionInfo.nodeJsSystemVersion &&
versionInfo.nodeJsSystemVersion !== versionInfo.nodeVersion
value: versionInfo.nodeJsSystemVersion
? `${versionInfo.nodeVersion} (System: ${versionInfo.nodeJsSystemVersion})`
: versionInfo.nodeVersion,
},
@ -66,21 +61,9 @@ export const AboutTab = () => {
];
const copyVersionInfo = async () => {
const nodeJsInfo =
versionInfo.nodeJsSystemVersion &&
versionInfo.nodeJsSystemVersion !== versionInfo.nodeVersion
? `${versionInfo.nodeVersion} (system: ${versionInfo.nodeJsSystemVersion})`
: versionInfo.nodeVersion;
const info = [
`${PRODUCT_NAME}: ${versionInfo.appVersion}`,
`Electron: ${versionInfo.electronVersion}`,
`Node.js: ${nodeJsInfo}`,
`Chromium: ${versionInfo.chromeVersion}`,
`V8: ${versionInfo.v8Version}`,
`OS: ${versionInfo.platform} ${versionInfo.arch} (${versionInfo.osVersion})`,
...(versionInfo.uvVersion ? [`uv: ${versionInfo.uvVersion}`] : []),
].join('\n');
const info = versionItems
.map((item) => `${item.label}: ${item.value}`)
.join('\n');
await safeExecute(
() => navigator.clipboard.writeText(info),
@ -128,15 +111,11 @@ export const AboutTab = () => {
leftSection={
<Github style={{ width: rem(16), height: rem(16) }} />
}
onClick={async () => {
await safeExecute(
() =>
onClick={() =>
window.electronAPI.app.openExternal(
'https://github.com/lone-cloud/gerbil'
),
'Failed to open GitHub link'
);
}}
)
}
style={{ textDecoration: 'none' }}
>
GitHub
@ -148,12 +127,7 @@ export const AboutTab = () => {
leftSection={
<FolderOpen style={{ width: rem(16), height: rem(16) }} />
}
onClick={async () => {
await safeExecute(
() => window.electronAPI.app.showLogsFolder(),
'Failed to open logs folder'
);
}}
onClick={() => window.electronAPI.app.showLogsFolder()}
>
Show Logs
</Button>

View file

@ -10,7 +10,6 @@ import {
} from '@mantine/core';
import { Sun, Moon, Monitor } from 'lucide-react';
import { useState, useEffect } from 'react';
import { safeExecute } from '@/utils/logger';
import { useAppColorScheme } from '@/hooks/useAppColorScheme';
import {
zoomLevelToPercentage,
@ -33,14 +32,8 @@ export const AppearanceTab = () => {
useEffect(() => {
const loadSettings = async () => {
const [currentZoom, savedColorScheme] = await Promise.all([
safeExecute(
() => window.electronAPI.app.getZoomLevel(),
'Failed to load zoom level:'
),
safeExecute(
() => window.electronAPI.app.getColorScheme(),
'Failed to load color scheme:'
),
window.electronAPI.app.getZoomLevel(),
window.electronAPI.app.getColorScheme(),
]);
if (typeof currentZoom === 'number') {
@ -56,38 +49,29 @@ export const AppearanceTab = () => {
void loadSettings();
}, []);
const handleColorSchemeChange = async (value: string) => {
const handleColorSchemeChange = (value: string) => {
const newColorScheme = value as MantineColorScheme;
setRawColorScheme(newColorScheme);
await safeExecute(
() => window.electronAPI.app.setColorScheme(newColorScheme),
'Failed to save color scheme:'
);
void window.electronAPI.app.setColorScheme(newColorScheme);
};
const handleZoomChange = async (newZoomLevel: number) => {
const handleZoomChange = (newZoomLevel: number) => {
setZoomLevel(newZoomLevel);
const percentage = zoomLevelToPercentage(newZoomLevel);
setZoomPercentage(percentage.toString());
await safeExecute(
() => window.electronAPI.app.setZoomLevel(newZoomLevel),
'Failed to set zoom level:'
);
void window.electronAPI.app.setZoomLevel(newZoomLevel);
};
const handleZoomPercentageChange = async (value: string) => {
const handleZoomPercentageChange = (value: string) => {
setZoomPercentage(value);
const numValue = Number(value);
if (!isNaN(numValue) && isValidZoomPercentage(numValue)) {
const newZoomLevel = percentageToZoomLevel(numValue);
setZoomLevel(newZoomLevel);
await safeExecute(
() => window.electronAPI.app.setZoomLevel(newZoomLevel),
'Failed to set zoom level:'
);
void window.electronAPI.app.setZoomLevel(newZoomLevel);
}
};

View file

@ -1,5 +1,5 @@
import { useState, useEffect, useCallback, useMemo } from 'react';
import { tryExecute, safeExecute } from '@/utils/logger';
import { tryExecute } from '@/utils/logger';
import {
Stack,
Text,
@ -99,11 +99,8 @@ export const GeneralTab = ({
for (const config of frontendConfigs) {
if (config.requirementCheck) {
const isAvailable = await safeExecute(
config.requirementCheck,
`Failed to check requirements for ${config.label}:`
);
requirementResults.set(config.value, isAvailable ?? false);
const isAvailable = await config.requirementCheck();
requirementResults.set(config.value, isAvailable);
} else {
requirementResults.set(config.value, true);
}
@ -163,20 +160,15 @@ export const GeneralTab = ({
}, [FrontendPreference, checkAllFrontendRequirements]);
const loadCurrentInstallDir = async () => {
const currentDir = await safeExecute(
() => window.electronAPI.kobold.getCurrentInstallDir(),
'Failed to load install directory:'
);
const currentDir = await window.electronAPI.kobold.getCurrentInstallDir();
if (currentDir) {
setInstallDir(currentDir);
}
};
const loadFrontendPreference = async () => {
const frontendPreference = await safeExecute(
() => window.electronAPI.config.get('frontendPreference'),
'Failed to load frontend preference:'
);
const frontendPreference =
await window.electronAPI.config.get('frontendPreference');
if (frontendPreference) {
setFrontendPreference(
(frontendPreference as FrontendPreference) || 'koboldcpp'
@ -185,10 +177,8 @@ export const GeneralTab = ({
};
const handleSelectInstallDir = async () => {
const selectedDir = await safeExecute(
() => window.electronAPI.kobold.selectInstallDirectory(),
'Failed to select install directory:'
);
const selectedDir =
await window.electronAPI.kobold.selectInstallDirectory();
if (selectedDir) {
setInstallDir(selectedDir);
}

View file

@ -16,7 +16,6 @@ import {
stripAssetExtensions,
compareVersions,
} from '@/utils/version';
import { safeExecute } from '@/utils/logger';
import { formatDownloadSize } from '@/utils/format';
import { useKoboldVersions } from '@/hooks/useKoboldVersions';
@ -60,7 +59,6 @@ export const VersionsTab = () => {
const loadInstalledVersions = useCallback(async () => {
setLoadingInstalled(true);
await safeExecute(async () => {
const [versions, currentVersion] = await Promise.all([
window.electronAPI.kobold.getInstalledVersions(),
window.electronAPI.kobold.getCurrentVersion(),
@ -68,16 +66,12 @@ export const VersionsTab = () => {
setInstalledVersions(versions);
setCurrentVersion(currentVersion);
}, 'Failed to load installed versions:');
setLoadingInstalled(false);
}, []);
const loadLatestRelease = useCallback(async () => {
const release = await safeExecute(
() => getLatestReleaseWithDownloadStatus(),
'Failed to load latest release:'
);
const release = await getLatestReleaseWithDownloadStatus();
if (release) {
setLatestRelease(release);
}
@ -174,11 +168,8 @@ export const VersionsTab = () => {
}, [downloading]);
const handleDownload = async (version: VersionInfo) => {
await safeExecute(async () => {
const download = availableDownloads.find((d) => d.name === version.name);
if (!download) {
throw new Error('Download not found');
}
if (!download) return;
const success = await sharedHandleDownload({
item: download,
@ -189,15 +180,11 @@ export const VersionsTab = () => {
if (success) {
await loadInstalledVersions();
}
}, 'Failed to download:');
};
const handleUpdate = async (version: VersionInfo) => {
await safeExecute(async () => {
const download = availableDownloads.find((d) => d.name === version.name);
if (!download) {
throw new Error('Download not found');
}
if (!download) return;
const success = await sharedHandleDownload({
item: download,
@ -208,21 +195,18 @@ export const VersionsTab = () => {
if (success) {
await loadInstalledVersions();
}
}, 'Failed to update:');
};
const makeCurrent = async (version: VersionInfo) => {
if (!version.installedPath) return;
await safeExecute(async () => {
const success = await window.electronAPI.kobold.setCurrentVersion(
version.installedPath!
version.installedPath
);
if (success) {
await loadInstalledVersions();
}
}, 'Failed to set current version:');
};
if (loadingInstalled || loadingPlatform || loadingRemote) {

View file

@ -1,6 +1,5 @@
import { useState, useEffect } from 'react';
import { useMantineColorScheme } from '@mantine/core';
import { safeExecute } from '@/utils/logger';
type ColorScheme = 'light' | 'dark';
@ -10,10 +9,7 @@ export const useAppColorScheme = () => {
useEffect(() => {
const loadColorScheme = async () => {
const rawScheme = await safeExecute(
() => window.electronAPI.app.getColorScheme(),
'Failed to get app color scheme'
);
const rawScheme = await window.electronAPI.app.getColorScheme();
if (rawScheme) {
let resolvedScheme: ColorScheme;

View file

@ -1,5 +1,5 @@
import { useState, useCallback, useEffect } from 'react';
import { safeExecute, tryExecute } from '@/utils/logger';
import { tryExecute } from '@/utils/logger';
import { compareVersions } from '@/utils/version';
import { GITHUB_API } from '@/constants';
@ -19,18 +19,12 @@ export const useAppUpdateChecker = () => {
useEffect(() => {
const initializeUpdater = async () => {
const [canUpdate, isDownloaded] = await Promise.all([
safeExecute(
() => window.electronAPI.updater.canAutoUpdate(),
'Failed to check auto-update capability'
),
safeExecute(
() => window.electronAPI.updater.isUpdateDownloaded(),
'Failed to check update download status'
),
window.electronAPI.updater.canAutoUpdate(),
window.electronAPI.updater.isUpdateDownloaded(),
]);
if (canUpdate !== null) setCanAutoUpdate(canUpdate);
if (isDownloaded !== null) setIsUpdateDownloaded(isDownloaded);
setCanAutoUpdate(canUpdate);
setIsUpdateDownloaded(isDownloaded);
};
void initializeUpdater();

View file

@ -1,5 +1,5 @@
import { useState, useCallback, useEffect } from 'react';
import { tryExecute, safeExecute } from '@/utils/logger';
import { tryExecute } from '@/utils/logger';
import {
getDisplayNameFromPath,
compareVersions,
@ -27,13 +27,9 @@ export const useUpdateChecker = () => {
useEffect(() => {
const loadDismissedUpdates = async () => {
const dismissed = await safeExecute(
async () =>
(await window.electronAPI.config.get('dismissedUpdates')) as
| string[]
| undefined,
'Failed to load dismissed updates'
);
const dismissed = (await window.electronAPI.config.get(
'dismissedUpdates'
)) as string[] | undefined;
if (dismissed) {
setDismissedUpdates(new Set(dismissed));

View file

@ -1,5 +1,4 @@
import { useEffect, useState, useCallback, useMemo } from 'react';
import { safeExecute } from '@/utils/logger';
import type { BackendOption, BackendSupport } from '@/types';
export interface Warning {
@ -105,10 +104,7 @@ const checkVramWarnings = async (backend: string): Promise<Warning[]> => {
const isGpuBackend = ['cuda', 'rocm', 'vulkan', 'clblast'].includes(backend);
if (isGpuBackend) {
const gpuMemoryInfo = await safeExecute(
() => window.electronAPI.kobold.detectGPUMemory(),
'Failed to detect GPU memory:'
);
const gpuMemoryInfo = await window.electronAPI.kobold.detectGPUMemory();
if (gpuMemoryInfo) {
const lowVramThreshold = 8;
@ -189,7 +185,6 @@ const checkBackendWarnings = async (params?: {
}): Promise<Warning[]> => {
const warnings: Warning[] = [];
const result = await safeExecute(async () => {
const [backendSupport, gpuCapabilities, gpuInfo] = await Promise.all([
window.electronAPI.kobold.detectBackendSupport(),
window.electronAPI.kobold.detectGPUCapabilities(),
@ -227,9 +222,6 @@ const checkBackendWarnings = async (params?: {
}
return warnings;
}, 'Failed to check backend warnings:');
return result || warnings;
};
export const useWarnings = ({
@ -253,7 +245,6 @@ export const useWarnings = ({
return;
}
const result = await safeExecute(async () => {
const [cpuCapabilitiesResult, availableBackends] = await Promise.all([
window.electronAPI.kobold.detectCPU(),
window.electronAPI.kobold.getAvailableBackends(),
@ -264,16 +255,15 @@ export const useWarnings = ({
avx2: cpuCapabilitiesResult.avx2,
};
return checkBackendWarnings({
const result = await checkBackendWarnings({
backend,
cpuCapabilities,
noavx2,
failsafe,
availableBackends,
});
}, 'Failed to check backend warnings:');
setBackendWarnings(result || []);
setBackendWarnings(result);
}, [backend, noavx2, failsafe]);
useEffect(() => {

View file

@ -37,7 +37,6 @@ setupAutoUpdater();
export const checkForUpdates = async () => {
if (isDevelopment) {
logError('Auto-updater: Cannot check for updates in development mode');
return false;
}
@ -51,7 +50,6 @@ export const checkForUpdates = async () => {
export const downloadUpdate = async () => {
if (isDevelopment) {
logError('Auto-updater: Cannot download updates in development mode');
return false;
}

View file

@ -1,21 +1,29 @@
import { app } from 'electron';
import { join } from 'path';
import { createLogger, format, type Logger } from 'winston';
import { mkdir } from 'fs/promises';
import { createLogger, format } from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
import { isDevelopment } from '@/utils/node/environment';
let logger: Logger | null = null;
let isInitialized = false;
export const initializeLogger = () => {
if (isInitialized) return;
const ensureLogsDirectory = async (logsDir: string) => {
try {
await mkdir(logsDir, { recursive: true });
} catch {
return;
}
};
const createAppLogger = () => {
const logsDir = join(app.getPath('userData'), 'logs');
logger = createLogger({
void ensureLogsDirectory(logsDir);
return createLogger({
level: isDevelopment ? 'debug' : 'info',
format: format.combine(
format.timestamp(),
format.timestamp({
format: 'YYYY-MM-DD HH:mm:ss.SSS',
}),
format.printf(({ timestamp, level, message, error }) => {
let logEntry = `${timestamp} [MAIN] [${level.toUpperCase()}] ${message}`;
@ -40,25 +48,17 @@ export const initializeLogger = () => {
}),
],
});
isInitialized = true;
};
const ensureInitialized = () => {
if (!isInitialized) {
initializeLogger();
}
};
const logger = createAppLogger();
export const logError = (message: string, error?: Error) => {
ensureInitialized();
logger!.error(message, { error });
logger.error(message, { error });
flushLogs();
};
export const flushLogs = () => {
ensureInitialized();
const fileTransport = logger!.transports.find(
const fileTransport = logger.transports.find(
(t) => t.constructor.name === 'DailyRotateFile'
);
if (

View file

@ -1,4 +1,4 @@
import { execa } from 'execa';
import { spawn } from 'child_process';
import { platform } from 'process';
import { safeExecute } from '@/utils/node/logger';
@ -12,16 +12,37 @@ const LINUX_PERFORMANCE_APPS = [
];
async function tryLaunchCommand(command: string, args: string[] = []) {
try {
await execa(command, args, {
return new Promise((resolve) => {
const child = spawn(command, args, {
detached: true,
stdio: 'ignore',
timeout: 2000,
});
return true;
} catch {
return false;
let hasResolved = false;
child.on('error', () => {
if (!hasResolved) {
hasResolved = true;
resolve(false);
}
});
child.on('spawn', () => {
if (!hasResolved) {
hasResolved = true;
child.unref();
resolve(true);
}
});
setTimeout(() => {
if (!hasResolved) {
hasResolved = true;
child.kill();
resolve(false);
}
}, 2000);
});
}
export const openPerformanceManager = async () =>

View file

@ -1,5 +1,4 @@
import { create } from 'zustand';
import { safeExecute } from '@/utils/logger';
import type { FrontendPreference } from '@/types';
interface FrontendPreferenceState {
@ -15,19 +14,15 @@ export const useFrontendPreferenceStore = create<FrontendPreferenceState>()(
setFrontendPreference: (preference: FrontendPreference) => {
set({ frontendPreference: preference });
safeExecute(async () => {
await window.electronAPI.config.set('frontendPreference', preference);
}, 'Error saving frontend preference:');
window.electronAPI.config.set('frontendPreference', preference);
},
loadFromConfig: async () => {
await safeExecute(async () => {
const preference = (await window.electronAPI.config.get(
'frontendPreference'
)) as FrontendPreference;
set({ frontendPreference: preference || 'koboldcpp' });
}, 'Error loading frontend preference:');
},
})
);

View file

@ -3,7 +3,7 @@ import {
createTryExecute,
createTryExecuteImmediate,
createSafeTryExecute,
} from '@/utils/shared/logger-core';
} from '@/utils/logger-core';
export const logError = (message: string, error: Error) => {
window.electronAPI.logs.logError(message, error);

View file

@ -3,7 +3,7 @@ import {
createSafeExecute,
createTryExecute,
createSafeTryExecute,
} from '@/utils/shared/logger-core';
} from '@/utils/logger-core';
export const safeExecute = createSafeExecute(logError);
export const tryExecute = createTryExecute(logError);