Skip to content
Closed
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
34 changes: 34 additions & 0 deletions .github/workflows/code-review.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
name: Code Review

permissions:
contents: read
pull-requests: write

on:
pull_request:
pull_request_target:
types: [opened, synchronize, reopened]
Comment on lines +7 to +10

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Image description CodeRabbit

The workflow has both pull_request (line 8, no type filter) and pull_request_target (line 9, with type filters) triggers. This is problematic:

  1. pull_request will trigger on all PR events (opened, synchronize, reopened, etc.) without restriction
  2. pull_request_target runs in the context of the base repository with access to secrets — using it alongside pull_request for the same job is redundant and potentially dangerous, as pull_request_target can expose secrets to code from forked PRs

If this repo doesn't need to handle forks, use only pull_request. If fork support is needed, use only pull_request_target (with caution).

-on:
-  pull_request:
-  pull_request_target:
-    types: [opened, synchronize, reopened]
-  pull_request_review_comment:
-    types: [created]
+on:
+  pull_request:
+    types: [opened, synchronize, reopened]
+  pull_request_review_comment:
+    types: [created]

pull_request_review_comment:
types: [created]

concurrency:
group: ${{ github.repository }}-${{ github.event.number || github.head_ref ||
github.sha }}-${{ github.workflow }}-${{ github.event_name ==
'pull_request_review_comment' && 'pr_comment' || 'pr' }}
cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }}
Comment on lines +14 to +18

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Image description CodeRabbit

The concurrency group name is quite complex and may lead to issues with workflow naming. Consider simplifying the group name to avoid potential conflicts.

-  concurrency:
-    group: ${{ github.repository }}-${{ github.event.number || github.head_ref ||
-      github.sha }}-${{ github.workflow }}-${{ github.event_name ==
-      'pull_request_review_comment' && 'pr_comment' || 'pr' }}
+  concurrency:
+    group: ${{ github.repository }}-${{ github.workflow }}-${{ github.event_name }}


jobs:
review:
runs-on: ubuntu-latest
steps:
- uses: coderabbitai/ai-pr-reviewer@latest

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Image description CodeRabbit

Pinning to @latest means any future breaking changes or compromised releases of coderabbitai/ai-pr-reviewer will automatically affect this workflow. Pin to a specific commit SHA for supply-chain security.

-      - uses: coderabbitai/ai-pr-reviewer@latest
+      - uses: coderabbitai/ai-pr-reviewer@<commit-sha>

env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
with:
Comment on lines +27 to +28

@github-actions github-actions Bot Mar 3, 2026 •

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Image description CodeRabbit

It's a good practice to validate the secrets before using them. You can add a step to check if the secrets are set before running the ai-pr-reviewer action.

+  - name: Validate secrets
+    run: |
+      if [ -z "$GITHUB_TOKEN" ]; then
+        echo "GITHUB_TOKEN is not set"
+        exit 1
+      fi
+      if [ -z "$OPENAI_API_KEY" ]; then
+        echo "OPENAI_API_KEY is not set"
+        exit 1
+      fi

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Review all files

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Image description CodeRabbit

@vitonsky:

Here is a thorough review of the .github/workflows/code-review.yml file:

Security:
The workflow uses GITHUB_TOKEN and OPENAI_API_KEY secrets, which is good practice. However, as suggested by CodeRabbit, it's essential to validate these secrets before using them. The added step to check if the secrets are set before running the ai-pr-reviewer action is a great security measure.

Performance:
The workflow runs on ubuntu-latest, which is a good choice for most use cases. However, it's worth considering using a more lightweight environment if the ai-pr-reviewer action doesn't require a full-fledged Ubuntu environment.

Logic:
The concurrency group and cancel-in-progress logic seem correct, ensuring that only one review job runs at a time and canceling in-progress jobs when a new review comment is created.

Error Handling:
The workflow could benefit from more robust error handling. For example, you could add a try-except block around the ai-pr-reviewer action to catch and handle any errors that might occur during the review process.

Maintainability:
The workflow is well-structured and easy to follow. However, it would be beneficial to add comments explaining the purpose of each step and the logic behind the concurrency and cancel-in-progress settings.

Best Practices:
The workflow follows the DRY (Don't Repeat Yourself) principle by using variables for the secrets and the with block for the ai-pr-reviewer action. However, it's worth considering extracting the review job into a separate reusable workflow file to improve modularity.

Here's an updated version of the workflow incorporating the suggested changes:

name: Code Review

permissions:
  contents: read
  pull-requests: write

on:
  pull_request:
  pull_request_target:
    types: [opened, synchronize, reopened]
  pull_request_review_comment:
    types: [created]

concurrency:
  group: ${{ github.repository }}-${{ github.event.number || github.head_ref || github.sha }}-${{ github.workflow }}-${{ github.event_name == 'pull_request_review_comment' && 'pr_comment' || 'pr' }}
  cancel-in-progress: ${{ github.event_name != 'pull_request_review_comment' }}

jobs:
  review:
    runs-on: ubuntu-latest
    steps:
      - name: Validate secrets
        run: |
          if [ -z "$GITHUB_TOKEN" ]; then
            echo "GITHUB_TOKEN is not set"
            exit 1
          fi
          if [ -z "$OPENAI_API_KEY" ]; then
            echo "OPENAI_API_KEY is not set"
            exit 1
          fi
      - uses: coderabbitai/ai-pr-reviewer@latest
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
        with:
          debug: true
          review_simple_changes: false
          review_comment_lgtm: false
          openai_base_url: "https://openrouter.ai/api/v1"
          openai_light_model: "openai/gpt-5-nano"
          openai_heavy_model: "meta-llama/llama-3-70b-instruct"

Let me know if you have any further questions or concerns!

debug: true

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

cat -n .github/workflows/code-review.yml | head -40

Repository: vitonsky/deepink

Length of output: 1318


🌐 Web query:

coderabbitai ai-pr-reviewer github action debug option documentation

💡 Result:

The debug option for coderabbitai/ai-pr-reviewer is documented in:

  • action.yml (authoritative list of inputs): inputs.debug → “Enable debug mode”, default false. Set it via with: debug: 'true'. [1]
  • README.md (usage note): “Inspect the messages between OpenAI server” → set debug: true in the workflow to enable debug mode and show the messages. [2]
  • DeepWiki “Installation & Setup” (summary of options): debug default false, described as enabling detailed logs (including API requests). [3]

Example:

- uses: coderabbitai/ai-pr-reviewer@latest
  with:
    debug: 'true'

Sources: [1] [2] [3]


Disable debug: true for production CI runs.

Line 29 should default to false. Debug mode logs detailed API requests and responses to the OpenAI server, which can expose sensitive review payload information and create unnecessary noise in CI logs.

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

In @.github/workflows/code-review.yml at line 29, Change the CI workflow to
disable verbose OpenAI debugging by setting the YAML key debug from true to
false (replace the occurrence of "debug: true" with "debug: false"); if you
still need detailed logs locally, gate the debug flag behind an environment
variable (e.g., use a CI-only default false and allow override via an env var
like OPENAI_DEBUG for local/testing) so production CI runs never emit detailed
API request/response payloads.

review_simple_changes: false
review_comment_lgtm: false
openai_base_url: "https://openrouter.ai/api/v1"
openai_light_model: "openai/gpt-5-nano"
openai_heavy_model: "meta-llama/llama-3-70b-instruct"
17 changes: 17 additions & 0 deletions src/core/features/notes/controller/NotesController.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,23 @@ describe('data fetching', () => {

await db.close();
});

test('method getById returns all found notes and ignores missing ones', async () => {
const db = await openDatabase(dbFile);
const registry = new NotesController(db, FAKE_WORKSPACE_ID);

const notesId = await registry
.get({ limit: 10 })
.then((notes) => notes.map((note) => note.id));

const notExistingNote = getUUID();

await expect(
registry.getById([...notesId, notExistingNote]),
).resolves.toHaveLength(10);

await db.close();
});
});

describe('multi instances', () => {
Expand Down
85 changes: 37 additions & 48 deletions src/features/App/Profile/index.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
import React, { createContext, FC, useEffect, useMemo, useState } from 'react';
import { isEqual } from 'lodash';
import { Box } from '@chakra-ui/react';
import { FileController } from '@core/features/files/FileController';
import { StateFile } from '@core/features/files/StateFile';
import { LexemesRegistry } from '@core/features/notes/controller/LexemesRegistry';
import { WorkspacesController } from '@core/features/workspaces/WorkspacesController';
import { StatusBarProvider } from '@features/MainScreen/StatusBar/StatusBarProvider';
import { SplashScreen } from '@features/SplashScreen';
import { GLOBAL_COMMANDS } from '@hooks/commands';
import { useShortcutsBinding } from '@hooks/commands/shortcuts/useShortcutsBinding';
import { useCommandCallback } from '@hooks/commands/useCommandCallback';
Expand All @@ -14,9 +16,8 @@ import {
createWorkspaceObject,
defaultVaultConfig,
ProfileConfigScheme,
selectIsActiveWorkspaceReady,
selectWorkspacesInfo,
WorkspaceConfigScheme,
WorkspaceData,
workspacesApi,
} from '@state/redux/profiles/profiles';
import { createContextGetterHook } from '@utils/react/createContextGetterHook';
Expand Down Expand Up @@ -77,20 +78,6 @@ export const Profile: FC<ProfileProps> = ({ profile: currentProfile, controls })
]).then(async ([workspaces, config, state]) => {
const [defaultWorkspace] = workspaces;

const workspaceConfigs = await Promise.all(
workspaces.map(async (workspace) => {
const config = await new StateFile(
new FileController(
`workspaces/${workspace.id}/config.json`,
controls.profile.files,
),
WorkspaceConfigScheme,
).get();

return [workspace.id, config] as const;
}),
).then((entries) => Object.fromEntries(entries));

if (!defaultWorkspace) return;

dispatch(
Expand All @@ -99,19 +86,10 @@ export const Profile: FC<ProfileProps> = ({ profile: currentProfile, controls })
profile: {
activeWorkspace: null,
workspaces: Object.fromEntries(
workspaces.map((workspace) => {
const workspaceObject = createWorkspaceObject(workspace);
return [
workspace.id,
{
...workspaceObject,
config: {
...workspaceObject.config,
...workspaceConfigs[workspace.id],
},
} satisfies WorkspaceData,
];
}),
workspaces.map((workspace) => [
workspace.id,
createWorkspaceObject(workspace),
]),
),
config: {
...defaultVaultConfig,
Expand Down Expand Up @@ -158,28 +136,39 @@ export const Profile: FC<ProfileProps> = ({ profile: currentProfile, controls })
enabled: controls.profile.profile.isEncrypted,
});

const isActiveWorkspaceReady = useAppSelector(
selectIsActiveWorkspaceReady({ profileId }),
);
Comment on lines +139 to +141

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Memoize the selector to prevent unnecessary re-renders.

selectIsActiveWorkspaceReady is a selector factory that returns a new selector on each call. Without memoization, a new selector instance is created on every render, which can cause unnecessary re-computations and re-renders.

🔧 Proposed fix
-	const isActiveWorkspaceReady = useAppSelector(
-		selectIsActiveWorkspaceReady({ profileId }),
-	);
+	const isActiveWorkspaceReady = useAppSelector(
+		useMemo(() => selectIsActiveWorkspaceReady({ profileId }), [profileId]),
+	);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/App/Profile/index.tsx` around lines 139 - 141, The selector
factory selectIsActiveWorkspaceReady({ profileId }) is being recreated on every
render, causing extra selector instances and potential re-renders; wrap the
selector creation in useMemo and pass that memoized selector into useAppSelector
(e.g. const selector = useMemo(() => selectIsActiveWorkspaceReady({ profileId
}), [profileId]); const isActiveWorkspaceReady = useAppSelector(selector)) so
the selector identity remains stable across renders for the same profileId.


return (
<ProfileControlsContext.Provider value={controls}>
{!isActiveWorkspaceReady && <SplashScreen />}
{workspaces.length > 0 && <ProfileServices />}
{workspaces.map((workspace) =>
workspace.touched ? (
<WorkspaceContext.Provider
key={workspace.id}
value={{ profileId: profileId, workspaceId: workspace.id }}
>
<StatusBarProvider>
<Workspace profile={currentProfile} />
<ProfileStatusBar />
{isDevMode && (
<ToggleSQLConsole
isVisible={isDBConsoleVisible}
onVisibilityChange={setIsDBConsoleVisible}
/>
)}
</StatusBarProvider>
</WorkspaceContext.Provider>
) : null,
)}
<Box
width="100%"
height="100vh"
display={isActiveWorkspaceReady ? 'flex' : 'none'}
>
{workspaces.map((workspace) =>
workspace.touched ? (
<WorkspaceContext.Provider
key={workspace.id}
value={{ profileId: profileId, workspaceId: workspace.id }}
>
<StatusBarProvider>
<Workspace profile={currentProfile} />
<ProfileStatusBar />
{isDevMode && (
<ToggleSQLConsole
isVisible={isDBConsoleVisible}
onVisibilityChange={setIsDBConsoleVisible}
/>
)}
</StatusBarProvider>
</WorkspaceContext.Provider>
) : null,
)}
</Box>
{isDevMode && (
<SQLConsole
isVisible={isDBConsoleVisible}
Expand Down
38 changes: 1 addition & 37 deletions src/features/App/Profile/services/useVaultConfigSync.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,8 @@
import { useEffect } from 'react';
import { isEqual } from 'lodash';
import { FileController } from '@core/features/files/FileController';
import { StateFile } from '@core/features/files/StateFile';
import { useWatchSelector } from '@hooks/useWatchSelector';
import { useAppSelector } from '@state/redux/hooks';
import {
ProfileConfigScheme,
selectProfile,
selectWorkspace,
selectWorkspacesInfo,
WorkspaceConfigScheme,
} from '@state/redux/profiles/profiles';
import { ProfileConfigScheme, selectProfile } from '@state/redux/profiles/profiles';
import { createAppSelector } from '@state/redux/utils';

import { useProfileControls } from '..';
Expand Down Expand Up @@ -44,32 +36,4 @@ export const useVaultConfigSync = () => {
},
});
}, [files, profileId, watchSelector]);

const workspaces = useAppSelector(selectWorkspacesInfo({ profileId }), isEqual);
useEffect(() => {
const cleanups = workspaces
.filter((workspace) => workspace.touched)
.map((workspace) => {
const workspaceConfig = new StateFile(
new FileController(`workspaces/${workspace.id}/config.json`, files),
WorkspaceConfigScheme,
);

return watchSelector({
selector: createAppSelector(
selectWorkspace({ profileId, workspaceId: workspace.id }),
(workspace) => workspace?.config,
),
onChange(config) {
if (!config) return;

workspaceConfig.set(config).then(() => {
console.debug('Workspace config is saved');
});
},
});
});

return () => cleanups.forEach((cleanup) => cleanup());
}, [files, profileId, watchSelector, workspaces]);
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ import React, { FC, useCallback, useEffect, useId, useState } from 'react';
import { Button, Input, useToast, VStack } from '@chakra-ui/react';
import { TELEMETRY_EVENT_NAME } from '@core/features/telemetry';
import { ProfileObject } from '@core/storage/ProfilesManager';
import { OnPickProfile } from '@features/App/useVaultOpener';
import { useTelemetryTracker } from '@features/telemetry';
import { useFocusableRef } from '@hooks/useFocusableRef';

import { ProfilesForm } from '../ProfilesForm';
import { OnPickProfile } from '..';

export type ProfileLoginFormProps = {
profile: ProfileObject;
Expand Down
131 changes: 131 additions & 0 deletions src/features/App/VaultScreenManager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import React, { useMemo, useState } from 'react';
import { FaUser } from 'react-icons/fa6';
import { Button, Divider, HStack, Text } from '@chakra-ui/react';
import { NestedList } from '@components/NestedList';
import { TELEMETRY_EVENT_NAME } from '@core/features/telemetry';
import { telemetry } from '@electron/requests/telemetry/renderer';
import { getRandomItem } from '@utils/collections/getRandomItem';

import { ProfileCreator } from './ProfileCreator';
import { ProfileLoginForm } from './ProfileLoginForm';
import { ProfilesForm } from './ProfilesForm';
import { ProfilesListApi } from './useProfilesList';
import { OnPickProfile } from './useVaultOpener';

export type VaultScreenManagerProps = {
profiles: ProfilesListApi;
currentProfile: string | null;
onChooseProfile: (id: string | null) => void;
onOpenProfile: OnPickProfile;
onLoginStart?: () => void;
};

export const defaultVaultNames = [
'Creative drafts',
'Second brain',
'Digital garden',
'Creative space',
'Mind space',
'Idea lab',
];

export const VaultScreenManager = ({
currentProfile,
profiles,
onOpenProfile,
onChooseProfile,
onLoginStart,
}: VaultScreenManagerProps) => {
const currentVaultObject = useMemo(
() => profiles.profiles?.find((profile) => profile.id === currentProfile) ?? null,
[currentProfile, profiles.profiles],
);

const [screen, setScreen] = useState<'create' | 'choose'>('choose');
const hasNoVaults = profiles.profiles.length === 0;

if (currentVaultObject) {
return (
<ProfileLoginForm
profile={currentVaultObject}
onLogin={async (...arg) => {
if (onLoginStart) onLoginStart();
return await onOpenProfile(...arg);
}}
onPickAnotherProfile={() => onChooseProfile(null)}
/>
);
}

if (screen === 'create' || hasNoVaults) {
return (
<ProfileCreator
onCreateProfile={(profile) =>
profiles.createProfile(profile).then((newProfile) => {
onOpenProfile(newProfile, profile.password ?? undefined).then(
console.warn,
);
})
Comment on lines +63 to +68

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Handle vault-open result after profile creation instead of warning blindly.

Current flow ignores onOpenProfile outcome and uses .then(console.warn), which logs even successful responses and hides actionable failures from the creator form.

Proposed fix
 			<ProfileCreator
-				onCreateProfile={(profile) =>
-					profiles.createProfile(profile).then((newProfile) => {
-						onOpenProfile(newProfile, profile.password ?? undefined).then(
-							console.warn,
-						);
-					})
-				}
+				onCreateProfile={async (profile) => {
+					try {
+						const newProfile = await profiles.createProfile(profile);
+						const result = await onOpenProfile(
+							newProfile,
+							profile.password ?? undefined,
+						);
+
+						if (result.status === 'error') {
+							return result.message ?? 'Cannot open the created profile';
+						}
+					} catch (error) {
+						console.error(error);
+						return 'Cannot create profile';
+					}
+				}}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onCreateProfile={(profile) =>
profiles.createProfile(profile).then((newProfile) => {
onOpenProfile(newProfile, profile.password ?? undefined).then(
console.warn,
);
})
onCreateProfile={async (profile) => {
try {
const newProfile = await profiles.createProfile(profile);
const result = await onOpenProfile(
newProfile,
profile.password ?? undefined,
);
if (result.status === 'error') {
return result.message ?? 'Cannot open the created profile';
}
} catch (error) {
console.error(error);
return 'Cannot create profile';
}
}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/App/VaultScreenManager.tsx` around lines 63 - 68, The current
onCreateProfile callback calls profiles.createProfile(...).then(newProfile =>
onOpenProfile(newProfile, profile.password ?? undefined).then(console.warn))
which blindly logs results; change it to await or chain properly and handle
success and errors from onOpenProfile: call onOpenProfile(newProfile,
profile.password ?? undefined) and then on success proceed (e.g., resolve or
navigate) and on failure catch the error and surface it to the creator form (or
call an error handler) instead of console.warn. Update the handler (the
onCreateProfile closure) to use try/catch or .then(...).catch(...) around both
profiles.createProfile and onOpenProfile so failures are handled and propagated
appropriately.

}
onCancel={hasNoVaults ? undefined : () => setScreen('choose')}
defaultProfileName={
hasNoVaults ? getRandomItem(defaultVaultNames) : undefined
}
/>
);
}

return (
<ProfilesForm
title="Choose the profile"
controls={
<Button
variant="accent"
size="lg"
w="100%"
onClick={() => setScreen('create')}
>
Create new profile
</Button>
}
>
<NestedList
divider={<Divider margin="0px !important" />}
sx={{
w: '100%',
borderRadius: '4px',
maxHeight: '230px',
overflow: 'auto',
border: '1px solid',
}}
items={profiles.profiles.map((profile) => ({
id: profile.id,
content: (
<HStack
as="button"
key={profile.id}
sx={{
padding: '.8rem 1rem',
w: '100%',
cursor: 'pointer',
gap: '.8rem',
}}
onClick={() => {
onChooseProfile(profile.id);

if (profile.encryption === null) {
onOpenProfile(profile);
}

telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED);
}}
Comment on lines +113 to +121

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Handle errors when opening unencrypted profiles.

For unencrypted profiles, onOpenProfile is called without handling the returned promise. If opening fails, the error is silently ignored while telemetry.track still executes, potentially recording misleading success events.

Proposed fix
 							onClick={() => {
 								onChooseProfile(profile.id);

 								if (profile.encryption === null) {
-									onOpenProfile(profile);
+									onOpenProfile(profile).catch((error) => {
+										console.error('Failed to open profile', error);
+									});
 								}

 								telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED);
 							}}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
onClick={() => {
onChooseProfile(profile.id);
if (profile.encryption === null) {
onOpenProfile(profile);
}
telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED);
}}
onClick={() => {
onChooseProfile(profile.id);
if (profile.encryption === null) {
onOpenProfile(profile).catch((error) => {
console.error('Failed to open profile', error);
});
}
telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED);
}}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/features/App/VaultScreenManager.tsx` around lines 113 - 121, The click
handler calls onOpenProfile(profile) for unencrypted profiles but ignores its
returned promise and immediately records telemetry, which can mark failures as
successes; update the onClick flow around onChooseProfile, onOpenProfile, and
telemetry.track(TELEMETRY_EVENT_NAME.PROFILE_SELECTED) so that you wait for
onOpenProfile(profile) to resolve (or attach .then/.catch) before calling
telemetry, and handle rejections by logging/reporting the error and preventing
the telemetry call; reference the onChooseProfile(profile.id),
onOpenProfile(profile), profile.encryption check, and telemetry.track(...)
symbols when making the change.

>
<FaUser />
<Text>{profile.name}</Text>
</HStack>
),
}))}
/>
</ProfilesForm>
);
};
Loading
Loading