Skip to content

Desktop, Mobile: Fixes #14506: Add the ability to delete the default profile#15153

Open
mrjo118 wants to merge 8 commits intolaurent22:devfrom
mrjo118:allow-deleting-default-profile
Open

Desktop, Mobile: Fixes #14506: Add the ability to delete the default profile#15153
mrjo118 wants to merge 8 commits intolaurent22:devfrom
mrjo118:allow-deleting-default-profile

Conversation

@mrjo118
Copy link
Copy Markdown
Contributor

@mrjo118 mrjo118 commented Apr 19, 2026

On both desktop and mobile, it is not possible to delete the default profile from the UI. This is because the default profile needs to be handled differently, because data from other profiles sit within the directory of the default profile, and some global settings are also stored there.

This PR implements deletion of the default profile, by 'resetting' the default profile, rather than removing the profile from the profile list. On desktop, this is done by explicitly removing the default profile specific directories and files by name, and replacing the settings.json with json just containing the global settings. On mobile, the same is done, except resources need special handling, but there is no settings file needed to be deleted / cleaned. As resources on the default profile exist at the root of the app directory, they are no isolated from global preferences and data from other profiles. Therefore, resources for deletion are detected by listing the files in the directory, and deleting any files which have a filename which is an alphanumeric string of exactly 32 characters without the extension. No shared files or files relating to other profiles meet this criteria, which make it a safe way to match the relevant items. Temporary encrypted resources also match this criteria, and will therefore be deleted as well.

After deleting the default profile, a popup is shown which says 'The default profile has been reset', in order to provide feedback to the user the action has completed, because the default profile remains in the list.

This fixes #14506

Testing

Scenarios tested:

  • Deleting the default profile, deletes the database and added resources - tested be checking changes to the storage space used by the app data, and exporting the debug profile while on the default profile. I also tested this with E2EE enabled and synced between 2 profiles, and verified that the crypted files are also deleted for the default profile
  • Deleting the default profile works when files do not exist - tested by deleting a second time immediately after
  • Deleting a normal profile works as per current behaviour
  • On desktop, I verified that when deleting the default profile, global settings are correctly retained when switching back to the default profile, but that the profile specific settings such as the sync target settings have been cleared
  • On mobile, verify that deleting the active profile presents an error (on desktop, the delete options is hidden for the active profile)
  • On mobile, I verified that sync target settings and editor font size is cleared down when clearing the default profile

Video on desktop:
https://github.com/user-attachments/assets/f5661990-c22f-4faa-8f1a-432fd53a75cb

Video on mobile:
https://github.com/user-attachments/assets/ab6e19d5-1015-4634-80d7-72f249e64924

@coderabbitai coderabbitai Bot added bug It's a bug enhancement Feature requests and code enhancements mobile All mobile platforms desktop All desktop platforms labels Apr 19, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/app-desktop/gui/ProfileEditor.tsx (1)

147-151: ⚠️ Potential issue | 🟡 Minor

Confirmation message does not reflect the default-profile "reset" semantics.

The same prompt — "Delete profile "%s"?\n\nAll data, including notes, notebooks and tags will be permanently deleted." — is shown for both sub-profile deletion and default-profile reset, but for the default profile the entry is kept and only selected data is cleared. Users may be surprised that the profile still appears afterwards, and the success popup "The default profile has been reset." conflicts with the earlier "delete" wording. Consider branching the confirmation message on isSubProfile(profile) so the default-profile path uses "reset" language consistently.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app-desktop/gui/ProfileEditor.tsx` around lines 147 - 151, The
confirmation uses the same "Delete profile" text for both sub-profiles and the
default profile; update the logic around the bridge().showConfirmMessageBox call
to branch on isSubProfile(profile) and show different language: for sub-profiles
keep the current delete wording with profile.name, and for the default profile
use "Reset default profile" / "Reset profile \"%s\"? ... Selected data will be
cleared and the profile entry will remain." Ensure the buttons and defaultId
remain appropriate and that the subsequent success popup still matches the
chosen action (e.g., "The default profile has been reset." when reset path is
taken).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/app-desktop/gui/ProfileEditor.tsx`:
- Around line 170-199: The reset currently only removes
dirsToDelete/filesToDelete and omits per-profile items (plugin-data, custom CSS
and keymap) and shows an error dialog for each failed deletion; update the
deletion logic in ProfileEditor.tsx to also delete the profile pluginDataDir
(plugin-data/), the custom CSS filenames from Settings.customCssFilenames (e.g.
userchrome.css, userstyle.css) and keymap-desktop.json (referencing the same
name used in app.ts), and aggregate any deletion errors into a single report
instead of calling bridge().showErrorMessageBox() inside each loop; keep using
shim.fsDriver().exists/ remove/ unlink but collect failures into an array, log
them with logger.error, and show one combined error dialog (or silent log as
mobile deleteProfile does) after both directory and file loops complete.

In `@packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.ts`:
- Around line 52-73: The current loop in deleteProfile.ts reads resourcesDir
with shim.fsDriver().readDirStats and attempts unlink via shim.fsDriver().unlink
but only logs failures (logger.error) causing the function to report success
even if deletions fail; change this to track per-file outcomes (e.g., count
successes and collect failed file paths/errors), and after the loop return or
throw an error (or surface a detailed failure message) if any unlink operations
failed so the caller/user is not misled by "The default profile has been reset."
Only log individual failures but also propagate an aggregate failure result.
Also tighten the filename check currently using /^[a-z0-9]{32}\./ by restricting
it to the actual Joplin hex-id pattern and allowed suffixes (for example use
[a-f0-9]{32}(?:\.crypted)? or explicitly validate the file extension) to avoid
accidental matches; update the regex used where fileName is tested. Ensure
references to resourcesDir, shim.fsDriver().readDirStats,
shim.fsDriver().unlink, logger.info and logger.error are preserved when
implementing these changes.

---

Outside diff comments:
In `@packages/app-desktop/gui/ProfileEditor.tsx`:
- Around line 147-151: The confirmation uses the same "Delete profile" text for
both sub-profiles and the default profile; update the logic around the
bridge().showConfirmMessageBox call to branch on isSubProfile(profile) and show
different language: for sub-profiles keep the current delete wording with
profile.name, and for the default profile use "Reset default profile" / "Reset
profile \"%s\"? ... Selected data will be cleared and the profile entry will
remain." Ensure the buttons and defaultId remain appropriate and that the
subsequent success popup still matches the chosen action (e.g., "The default
profile has been reset." when reset path is taken).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: db038f70-eb25-4b72-b811-3c5378e400dc

📥 Commits

Reviewing files that changed from the base of the PR and between 44a5a8a and db80d15.

📒 Files selected for processing (4)
  • packages/app-desktop/gui/ProfileEditor.tsx
  • packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.test.ts
  • packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.ts
  • packages/lib/services/profileConfig/index.ts
💤 Files with no reviewable changes (2)
  • packages/lib/services/profileConfig/index.ts
  • packages/app-mobile/components/ProfileSwitcher/utils/deleteProfile.test.ts

Comment thread packages/app-desktop/gui/ProfileEditor.tsx
@github-actions github-actions Bot deleted a comment from coderabbitai Bot Apr 19, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/app-desktop/gui/ProfileEditor.tsx (1)

101-112: ⚠️ Potential issue | 🟠 Major

Persist the profile removal before deleting its directory.

If Line 161 succeeds but Line 168 fails inside saveNewProfileConfig, the profile remains in profiles.json while its data directory is gone. Save the config first and only continue with destructive deletion when that succeeds.

🐛 Proposed fix
-	const saveNewProfileConfig = async (makeNewProfileConfig: ()=> ProfileConfig) => {
+	const saveNewProfileConfig = async (makeNewProfileConfig: ()=> ProfileConfig): Promise<boolean> => {
 		try {
 			const newProfileConfig = makeNewProfileConfig();
 			await saveProfileConfig(`${Setting.value('rootProfileDir')}/profiles.json`, newProfileConfig);
 			dispatch({
 				type: 'PROFILE_CONFIG_SET',
 				value: newProfileConfig,
 			});
+			return true;
 		} catch (error) {
 			logger.error(error);
 			bridge().showErrorMessageBox(error.message);
+			return false;
 		}
 	};
 		if (subProfile) {
 			const profileDir = `${rootDir}/profile-${profile.id}`;
 
+			if (!await saveNewProfileConfig(() => deleteProfileById(profileConfig, profile.id))) return;
+
 			try {
 				await shim.fsDriver().remove(profileDir);
 				logger.info('Deleted profile directory: ', profileDir);
 			} catch (error) {
 				logger.error('Error deleting profile directory: ', error);
 				bridge().showErrorMessageBox(error.message);
 			}
-
-			await saveNewProfileConfig(() => deleteProfileById(profileConfig, profile.id));
 		} else {

Also applies to: 160-168

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app-desktop/gui/ProfileEditor.tsx` around lines 101 - 112,
saveNewProfileConfig currently performs destructive deletion before guaranteeing
the updated profiles.json is persisted; change the flow so you persist the new
ProfileConfig first (using saveProfileConfig inside saveNewProfileConfig and
then dispatch the 'PROFILE_CONFIG_SET' action) and only after that await the
destructive removal of the profile directory (the deletion code currently at
lines ~160-168). In practice: call saveNewProfileConfig (which must complete the
save and dispatch) before invoking the directory deletion routine (fs.rm/rimraf
or whatever deletion helper you use), and if the deletion fails
handle/log/showErrorMessageBox without rolling back the saved profiles.json.
♻️ Duplicate comments (1)
packages/app-desktop/gui/ProfileEditor.tsx (1)

170-201: ⚠️ Potential issue | 🟠 Major

Default reset still leaves some profile data behind and can show a false success message.

keymap-desktop.json is now covered, but plugin-data/ and custom CSS files still persist after reset. Also, failed deletions at Lines 183 and 197 are followed by the success message at Line 201.

🐛 Proposed fix
-			const dirsToDelete = ['cache', 'JoplinBackup', 'resources', 'tmp'];
-			const filesToDelete = ['database.sqlite', 'log.txt', 'settings.json', 'keymap-desktop.json'];
+			const dirsToDelete = ['cache', 'JoplinBackup', 'resources', 'tmp', 'plugin-data'];
+			const filesToDelete = ['database.sqlite', 'log.txt', 'settings.json', 'keymap-desktop.json', ...Setting.customCssFilenames];
+			const deletionErrors: string[] = [];
 
 			// Delete directories
 			for (const dir of dirsToDelete) {
 				const fullPath = `${rootDir}/${dir}`;
 				try {
 					if (await shim.fsDriver().exists(fullPath)) {
 						await shim.fsDriver().remove(fullPath);
 						logger.info('Deleted directory: ', fullPath);
 					}
 				} catch (error) {
 					logger.error('Error deleting directory: ', fullPath, error);
-					bridge().showErrorMessageBox(error.message);
+					const message = error instanceof Error ? error.message : String(error);
+					deletionErrors.push(`${fullPath}: ${message}`);
 				}
 			}
 
 			// Delete files
 			for (const file of filesToDelete) {
 				const fullPath = `${rootDir}/${file}`;
 				try {
 					if (await shim.fsDriver().exists(fullPath)) {
 						await shim.fsDriver().unlink(fullPath);
 						logger.info('Deleted file: ', fullPath);
 					}
 				} catch (error) {
 					logger.error('Error deleting file: ', fullPath, error);
-					bridge().showErrorMessageBox(error.message);
+					const message = error instanceof Error ? error.message : String(error);
+					deletionErrors.push(`${fullPath}: ${message}`);
 				}
 			}
 
+			if (deletionErrors.length) {
+				bridge().showErrorMessageBox(_('Some profile data could not be deleted:\n\n%s', deletionErrors.join('\n')));
+				return;
+			}
+
 			bridge().showMessageBox(_('The default profile has been reset.'));
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/app-desktop/gui/ProfileEditor.tsx` around lines 170 - 201, The reset
currently only targets dirsToDelete and filesToDelete and always shows
bridge().showMessageBox('The default profile has been reset.') even if deletions
failed; update the cleanup to include the plugin-data directory and common
custom CSS filenames (e.g., custom.css, userstyle.css) by adding them to
dirsToDelete/filesToDelete (use rootDir + '/plugin-data' and rootDir +
'/.config' entries as appropriate), track any deletion errors with a boolean
flag or an errors array while using shim.fsDriver().exists/remove/unlink and
logger, and only call bridge().showMessageBox(...) when no errors occurred
(otherwise call bridge().showErrorMessageBox with the aggregated error
messages); refer to the existing variables dirsToDelete, filesToDelete, rootDir,
shim.fsDriver(), logger and bridge() to locate and modify the code.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/app-desktop/gui/ProfileEditor.tsx`:
- Around line 101-112: saveNewProfileConfig currently performs destructive
deletion before guaranteeing the updated profiles.json is persisted; change the
flow so you persist the new ProfileConfig first (using saveProfileConfig inside
saveNewProfileConfig and then dispatch the 'PROFILE_CONFIG_SET' action) and only
after that await the destructive removal of the profile directory (the deletion
code currently at lines ~160-168). In practice: call saveNewProfileConfig (which
must complete the save and dispatch) before invoking the directory deletion
routine (fs.rm/rimraf or whatever deletion helper you use), and if the deletion
fails handle/log/showErrorMessageBox without rolling back the saved
profiles.json.

---

Duplicate comments:
In `@packages/app-desktop/gui/ProfileEditor.tsx`:
- Around line 170-201: The reset currently only targets dirsToDelete and
filesToDelete and always shows bridge().showMessageBox('The default profile has
been reset.') even if deletions failed; update the cleanup to include the
plugin-data directory and common custom CSS filenames (e.g., custom.css,
userstyle.css) by adding them to dirsToDelete/filesToDelete (use rootDir +
'/plugin-data' and rootDir + '/.config' entries as appropriate), track any
deletion errors with a boolean flag or an errors array while using
shim.fsDriver().exists/remove/unlink and logger, and only call
bridge().showMessageBox(...) when no errors occurred (otherwise call
bridge().showErrorMessageBox with the aggregated error messages); refer to the
existing variables dirsToDelete, filesToDelete, rootDir, shim.fsDriver(), logger
and bridge() to locate and modify the code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d58baad7-5793-4f05-86f2-5b5e8a0ea997

📥 Commits

Reviewing files that changed from the base of the PR and between db80d15 and d01e604.

📒 Files selected for processing (1)
  • packages/app-desktop/gui/ProfileEditor.tsx

@github-actions github-actions Bot deleted a comment from coderabbitai Bot Apr 19, 2026
@github-actions github-actions Bot deleted a comment from coderabbitai Bot Apr 19, 2026
await saveNewProfileConfig(() => deleteProfileById(profileConfig, profile.id));
} else {
const dirsToDelete = ['cache', 'JoplinBackup', 'resources', 'tmp'];
const filesToDelete = ['database.sqlite', 'log.txt', 'settings.json', 'keymap-desktop.json'];
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

'settings.json'

Some settings are marked with isGlobal: true, which causes these settings to be shared across profiles. Does deleting the toplevel settings.json clear these global settings?

Copy link
Copy Markdown
Contributor Author

@mrjo118 mrjo118 Apr 20, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are correct, deleting the settings.json of the default profile does clear those settings. I have now pushed up a change to address this

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/lib/models/Setting.ts (1)

1134-1224: Extracted helper has hidden side effects when reused from resetDefaultProfileSettings.

getFileValuesAndDbUpdateQueries isn't purely a getter — the inner loop writes secure values to the keychain (lines 1161–1168) and, on keychain failure, adds INSERT queries to queries as a fallback. When called from resetDefaultProfileSettings, the queries array (including the keychain-failure fallback inserts) is discarded, yet the keychain writes still execute using the current profile's cached secure values. In practice this is idempotent and harmless (the active profile can't be the default, so we're just rewriting the running sub-profile's existing keychain entries), but:

  1. The name suggests pure value/query computation, masking the side effect.
  2. A future keychain outage during reset would silently drop the DB-fallback path for secure keys (queries are thrown away), which differs from saveAll's guarantees.

Consider splitting the helper so resetDefaultProfileSettings reuses only the pure "build valuesForFile from cache" portion, leaving the keychain/DB side effects in saveAll.

Also — this design correctly addresses the earlier question about isGlobal settings: splitGlobalAndLocalSettings(valuesForFile) + overwrite: true preserves shared global settings in the root settings.json while wiping the default profile's local settings. 👍

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/lib/models/Setting.ts` around lines 1134 - 1224,
getFileValuesAndDbUpdateQueries performs side effects (writing to keychain and
pushing DB fallback queries) which are inappropriate when called from
resetDefaultProfileSettings; split the helper into two: a pure getter (e.g.,
buildValuesForFileFromCache or getValuesForFileOnly) that returns only
valuesForFile based on this.cache_ and this.keyStorage/key checks, and a
separate method (e.g., getDbUpdateQueriesWithKeychainWrites or
applyKeychainAndBuildQueries) that performs the keychain writes and builds the
queries; then update saveAll to call both the pure getter and the side-effecting
method to get queries, while making resetDefaultProfileSettings call only the
pure getter and then use splitGlobalAndLocalSettings as before so no keychain
writes or discarded DB queries occur during reset.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/lib/models/settings/FileHandler.ts`:
- Around line 81-87: The overwrite branch in save() stores Setting.schemaUrl
into this.parsedJsonCache_, causing an inconsistent cache shape; update the
overwrite path in FileHandler.save (the block that sets this.parsedJsonCache_)
to omit the '$schema' key before assigning (i.e., spread values but
filter/delete '$schema' or create a new object excluding '$schema'), so
parsedJsonCache_ matches the shape produced by load() and avoids reintroducing
'$schema' during the merge loop in save().

---

Nitpick comments:
In `@packages/lib/models/Setting.ts`:
- Around line 1134-1224: getFileValuesAndDbUpdateQueries performs side effects
(writing to keychain and pushing DB fallback queries) which are inappropriate
when called from resetDefaultProfileSettings; split the helper into two: a pure
getter (e.g., buildValuesForFileFromCache or getValuesForFileOnly) that returns
only valuesForFile based on this.cache_ and this.keyStorage/key checks, and a
separate method (e.g., getDbUpdateQueriesWithKeychainWrites or
applyKeychainAndBuildQueries) that performs the keychain writes and builds the
queries; then update saveAll to call both the pure getter and the side-effecting
method to get queries, while making resetDefaultProfileSettings call only the
pure getter and then use splitGlobalAndLocalSettings as before so no keychain
writes or discarded DB queries occur during reset.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 3cdd61b8-5737-4ee2-812c-d10376a7bf3e

📥 Commits

Reviewing files that changed from the base of the PR and between 29c0312 and 38fa4a3.

📒 Files selected for processing (3)
  • packages/app-desktop/gui/ProfileEditor.tsx
  • packages/lib/models/Setting.ts
  • packages/lib/models/settings/FileHandler.ts

Comment thread packages/lib/models/settings/FileHandler.ts
@github-actions github-actions Bot deleted a comment from coderabbitai Bot Apr 20, 2026
@github-actions github-actions Bot deleted a comment from coderabbitai Bot Apr 20, 2026
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/lib/models/settings/FileHandler.ts (1)

56-85: ⚠️ Potential issue | 🟡 Minor

parsedJsonCache_ can become stale relative to valueJsonCache_ on the non-overwrite path.

After a non-overwrite save(), valueJsonCache_ is refreshed (line 79) but parsedJsonCache_ is left untouched. If values introduces any key not already present in parsedJsonCache_, a subsequent load() will short-circuit at line 34 and return the stale cached object, which is missing the newly saved keys (and any value updates for keys already in the cache, since the merge loop only fills in keys absent from values). Prior behaviour unconditionally replaced the cache, so this is a behavioural regression for the default path.

Consider updating parsedJsonCache_ on both paths (it already reflects the merged values after the loop):

🛠️ Proposed fix
 		await shim.fsDriver().writeFile(this.filePath_, json, 'utf8');
 		this.valueJsonCache_ = json;
-
-		if (overwrite) {
-			// Prevent pre-existing settings from being re-instated by subsequent saving of settings
-			this.parsedJsonCache_ = values;
-		}
+		// Keep parsedJsonCache_ in sync with what was just written. On the overwrite path this
+		// also prevents pre-existing settings from being re-instated by subsequent saves.
+		this.parsedJsonCache_ = values;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/lib/models/settings/FileHandler.ts` around lines 56 - 85, The save()
method updates valueJsonCache_ but on the non-overwrite path it never updates
parsedJsonCache_, causing the parsed cache to remain stale; after the merge loop
and successful write (i.e. after await shim.fsDriver().writeFile(...) and
setting this.valueJsonCache_), assign the merged values into
this.parsedJsonCache_ (this.parsedJsonCache_ = values) so parsedJsonCache_
reflects the newly saved/merged settings; keep the existing overwrite-specific
assignment but ensure parsedJsonCache_ is updated on the general save path as
well.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@packages/lib/models/settings/FileHandler.ts`:
- Around line 56-85: The save() method updates valueJsonCache_ but on the
non-overwrite path it never updates parsedJsonCache_, causing the parsed cache
to remain stale; after the merge loop and successful write (i.e. after await
shim.fsDriver().writeFile(...) and setting this.valueJsonCache_), assign the
merged values into this.parsedJsonCache_ (this.parsedJsonCache_ = values) so
parsedJsonCache_ reflects the newly saved/merged settings; keep the existing
overwrite-specific assignment but ensure parsedJsonCache_ is updated on the
general save path as well.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e756583f-1239-4ee9-a96c-04809df50f7e

📥 Commits

Reviewing files that changed from the base of the PR and between 38fa4a3 and a69b2df.

📒 Files selected for processing (1)
  • packages/lib/models/settings/FileHandler.ts

@github-actions github-actions Bot deleted a comment from coderabbitai Bot Apr 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug It's a bug desktop All desktop platforms enhancement Feature requests and code enhancements mobile All mobile platforms

Projects

None yet

Development

Successfully merging this pull request may close these issues.

The default profile should be able to be deleted in the manage profiles screen

2 participants