Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add default node storage location preference #690

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions assets/locales/en/translation.json
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@
"PreReleaseUpdatesDescription": "Disabled by default. Enable to update and test pre-release versions of the app. Pre-releases are more likely to have issues.",
"YouAreRunningNiceNode": "You are running NiceNode",
"NoNotificationsYet": "No notifications yet",
"WellLetYouKnow": "Well let you know when something interesting happens!",
"WellLetYouKnow": "We'll let you know when something interesting happens!",
"MarkAllAsRead": "Mark all as read",
"ClearNotifications": "Clear notifications",
"NotificationPreferences": "Notification preferences",
Expand All @@ -97,7 +97,7 @@
"BlockExplorer": "Block Explorer",
"BrowserExtensionId": "Browser Extension ID",
"UnableSetWalletConnections": "Unable to set wallet connections for this node. This node is missing configuration values for this feature.",
"WalletDescription": "Connect your browser wallet to this node so you can enjoy greater security, privacy, and read speeds. Enable your favourite browser wallets below to allow access to your node. Dont forget to add a new network in your wallet with the configuration below.",
"WalletDescription": "Connect your browser wallet to this node so you can enjoy greater security, privacy, and read speeds. Enable your favourite browser wallets below to allow access to your node. Don't forget to add a new network in your wallet with the configuration below.",
"UsingLesserKnownWallet": "Using a lesser known wallet?",
"SelectBrowser": "If your wallet of choice is not displayed in the list above you can select the browser used for the extension and provide the extension ID to allow access.",
"AddRow": "Add Row",
Expand Down Expand Up @@ -154,7 +154,7 @@
"NodeRequirements": "Node Requirements",
"NodeStartCommand": "Node start command (must save changes to take effect)",
"ResetToDefaults": "Reset to defaults",
"AddBaseNodeDescription": "Base is a secure, low-cost, developer-friendly Ethereum L2 built to bring the next billion users onchain. It's built on Optimisms open-source OP Stack.",
"AddBaseNodeDescription": "Base is a secure, low-cost, developer-friendly Ethereum L2 built to bring the next billion users onchain. It's built on Optimism's open-source OP Stack.",
"LaunchAVarNode": "Launch a {{nodeName}} Node",
"AddNodeDescription": "Support the health of a network protocol by running a node.",
"InitialSyncStarted": "Initial sync process started",
Expand All @@ -180,5 +180,11 @@
"RunningLatestVersion": "You are running the latest version",
"SuccessfullyUpdated": "Successfully updated",
"Done": "Done",
"Close": "Close"
"Close": "Close",
"Storage": "Storage",
"DefaultNodeStorage": "Default Node Storage Location",
"DefaultNodeStorageDescription": "The default location where node data will be stored. This can be changed per node in node settings.",
"NoWritePermissions": "Permission Denied",
"NoWritePermissionsMessage": "Cannot write to selected folder",
"NoWritePermissionsDetail": "NiceNode does not have permission to write to the selected folder: {{path}}\n\nPlease select a different folder or check the folder permissions."
}
44 changes: 35 additions & 9 deletions src/main/dialog.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { type BrowserWindow, dialog } from 'electron';
import { access, constants } from 'node:fs/promises';

import type Node from '../common/node';
import type { NodeId } from '../common/node';
Expand Down Expand Up @@ -61,6 +62,18 @@ export const openDialogForNodeDataDir = async (nodeId: NodeId) => {
return;
};

export const checkWritePermissions = async (
folderPath: string,
): Promise<boolean> => {
try {
await access(folderPath, constants.W_OK);
return true;
} catch (err) {
logger.error(`No write permissions for path ${folderPath}:`, err);
return false;
}
};

export const openDialogForStorageLocation = async (): Promise<
CheckStorageDetails | undefined
> => {
Expand All @@ -77,19 +90,32 @@ export const openDialogForStorageLocation = async (): Promise<
defaultPath,
properties: ['openDirectory'],
});
console.log('dir select result: ', result);

if (result.canceled) {
return;
}
if (result.filePaths) {
if (result.filePaths.length > 0) {
const folderPath = result.filePaths[0];
const freeStorageGBs = await getSystemFreeDiskSpace(folderPath);
return {
folderPath,
freeStorageGBs,
};

if (result.filePaths && result.filePaths.length > 0) {
const folderPath = result.filePaths[0];

// Check write permissions
const hasWritePermissions = await checkWritePermissions(folderPath);
if (!hasWritePermissions) {
// Show error dialog to user
await dialog.showMessageBox(mainWindow, {
type: 'error',
title: t('NoWritePermissions'),
message: t('NoWritePermissionsMessage'),
detail: t('NoWritePermissionsDetail', { path: folderPath }),
});
return;
}

const freeStorageGBs = await getSystemFreeDiskSpace(folderPath);
return {
folderPath,
freeStorageGBs,
};
}

return;
Expand Down
11 changes: 10 additions & 1 deletion src/main/files.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { app } from 'electron';
import logger from './logger';

import du from 'du';
import store from './state/store';

logger.info(`App data dir: ${app.getPath('appData')}`);
logger.info(`User data dir: ${app.getPath('userData')}`);
Expand All @@ -27,7 +28,15 @@ export const getNNDirPath = (): string => {
* @returns getNNDirPath + '/nodes'
*/
export const getNodesDirPath = (): string => {
return path.join(getNNDirPath(), 'nodes');
// First check if user has set a custom default location
const userDefaultLocation = store.get('appDefaultStorageLocation');
if (userDefaultLocation) {
return userDefaultLocation;
}

// Fall back to default app storage location
const userDataPath = app.getPath('userData');
return path.join(userDataPath, 'nodes');
};

export const checkAndOrCreateDir = async (dirPath: string) => {
Expand Down
9 changes: 9 additions & 0 deletions src/main/ipc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import {
import { getSetIsDeveloperModeEnabled } from './state/settings.js';
import store from './state/store';
import { getSystemInfo } from './systemInfo';
import { setDefaultStorageLocation } from './state/settings';

export const initialize = () => {
ipcMain.handle(
Expand Down Expand Up @@ -285,4 +286,12 @@ export const initialize = () => {
ipcMain.handle('checkPorts', (_event, ports: number[]) => {
return checkPorts(ports);
});

// Add to the initialize function
ipcMain.handle(
'setDefaultStorageLocation',
(_event, storageLocation: string) => {
return setDefaultStorageLocation(storageLocation);
},
);
};
3 changes: 3 additions & 0 deletions src/main/preload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,4 +184,7 @@ contextBridge.exposeInMainWorld('electron', {
checkPorts: (ports: number[]) => {
ipcRenderer.invoke('checkPorts', ports);
},

setDefaultStorageLocation: (storageLocation: string) =>
ipcRenderer.invoke('setDefaultStorageLocation', storageLocation),
});
10 changes: 8 additions & 2 deletions src/main/state/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ const APP_IS_NOTIFICATIONS_ENABLED = 'appIsNotificationsEnabled';
export const APP_IS_EVENT_REPORTING_ENABLED = 'appIsEventReportingEnabled';
const APP_IS_PRE_RELEASE_UPDATES_ENABLED = 'appIsPreReleaseUpdatesEnabled';
export const APP_IS_DEVELOPER_MODE_ENABLED = 'appIsDeveloperModeEnabled';
const APP_DEFAULT_STORAGE_LOCATION = 'appDefaultStorageLocation';

export type ThemeSetting = 'light' | 'dark' | 'auto';
export type Settings = {
export interface Settings {
[OS_PLATFORM_KEY]?: string;
[OS_ARCHITECTURE]?: string;
[OS_LANGUAGE_KEY]?: string;
Expand All @@ -39,7 +40,8 @@ export type Settings = {
[APP_IS_EVENT_REPORTING_ENABLED]?: boolean;
[APP_IS_PRE_RELEASE_UPDATES_ENABLED]?: boolean;
[APP_IS_DEVELOPER_MODE_ENABLED]?: boolean;
};
[APP_DEFAULT_STORAGE_LOCATION]?: string;
}

/**
* Called on app launch.
Expand Down Expand Up @@ -209,6 +211,10 @@ export const getSetIsDeveloperModeEnabled = (
return savedIsDeveloperModeEnabled;
};

export const setDefaultStorageLocation = (storageLocation: string) => {
store.set('appDefaultStorageLocation', storageLocation);
};

// listen to OS theme updates
nativeTheme.on('updated', () => {
console.log("nativeTheme.on('updated')");
Expand Down
Loading
Loading