From fbb51a0b4c9f817c6c3c6f2345632b9f21815ee6 Mon Sep 17 00:00:00 2001 From: lucaronin Date: Tue, 26 May 2026 10:11:53 +0200 Subject: [PATCH] fix: resolve codacy high severity findings --- SECURITY.md | 2 +- biome.json | 38 +++++ e2e/core-flows.spec.ts | 2 +- e2e/visual-verify.spec.ts | 2 +- index.html | 13 +- package.json | 11 +- pnpm-lock.yaml | 79 ++++----- src-tauri/Cargo.lock | 3 - src-tauri/Cargo.toml | 5 - src-tauri/src/app_icon.rs | 38 ----- src-tauri/src/git/mod.rs | 6 +- src-tauri/src/mcp.rs | 64 ++----- src-tauri/src/mcp/paths.rs | 21 +-- src-tauri/src/settings.rs | 11 +- src/App.tsx | 27 ++- src/components/AddPropertyForm.tsx | 6 +- src/components/AiActionCard.tsx | 16 +- src/components/AiMessage.tsx | 7 +- src/components/AiPanelChrome.tsx | 2 + src/components/AiProviderSettings.tsx | 19 ++- src/components/ArchivedNoteBanner.tsx | 2 +- src/components/BreadcrumbBar.tsx | 22 ++- src/components/ColorInput.tsx | 118 +++++++++---- src/components/CommandPalette.tsx | 32 +++- src/components/CommitDialog.tsx | 9 +- src/components/ConflictNoteBanner.tsx | 4 +- .../ConflictResolverModal.keyboard.test.tsx | 6 +- src/components/ConflictResolverModal.tsx | 44 ++--- src/components/CreateNoteDialog.tsx | 10 +- src/components/CreateTypeDialog.tsx | 6 +- src/components/CreateViewDialog.tsx | 8 +- src/components/DiffView.tsx | 2 +- src/components/DynamicPropertiesPanel.tsx | 14 +- src/components/EditableValue.tsx | 57 ++++--- src/components/Editor.test.tsx | 2 +- src/components/FilePreview.tsx | 54 +++--- src/components/FilterBuilder.tsx | 8 +- src/components/FilterFieldCombobox.tsx | 35 ++-- src/components/FolderTree.tsx | 2 +- src/components/GitRepositorySelect.tsx | 6 +- src/components/IconEditableValue.tsx | 7 +- src/components/InlineWikilinkInput.tsx | 2 + src/components/InlineWikilinkParts.tsx | 146 ++++++++++++---- src/components/LinuxMenuButton.test.tsx | 4 +- src/components/LinuxMenuButton.tsx | 14 +- src/components/LinuxTitlebar.tsx | 12 +- src/components/MarkdownContent.tsx | 28 +-- src/components/McpSetupDialog.tsx | 1 - src/components/MermaidDiagram.test.tsx | 4 +- src/components/MermaidDiagram.tsx | 14 +- src/components/NoteAutocomplete.tsx | 5 +- src/components/NoteIcon.tsx | 4 +- src/components/NoteItem.tsx | 19 ++- src/components/NoteSearchList.tsx | 67 ++++---- src/components/OnboardingShell.tsx | 20 ++- src/components/PrivacySettingsSection.tsx | 7 +- .../PropertyValueCells.extra.test.tsx | 20 +-- src/components/PropertyValueCells.test.tsx | 14 +- src/components/PropertyValueCells.tsx | 160 ++++++++++++------ src/components/PulseView.test.tsx | 8 +- src/components/PulseView.tsx | 123 +++++++------- src/components/QuickOpenPalette.tsx | 25 ++- src/components/RawEditorFindBar.tsx | 35 ++-- .../RawEditorView.behavior.test.tsx | 2 +- .../RawEditorView.coverage.test.tsx | 2 +- src/components/RawEditorView.tsx | 30 +++- src/components/RenameDetectedBanner.tsx | 4 +- src/components/ResizeHandle.tsx | 12 +- src/components/SearchPanel.tsx | 35 +++- src/components/SettingsControls.tsx | 20 ++- src/components/SettingsPanel.tsx | 50 ++++-- src/components/SidebarParts.tsx | 47 +++-- src/components/SingleEditorView.tsx | 16 +- src/components/StatusDropdown.tsx | 19 ++- src/components/TagsDropdown.tsx | 17 +- src/components/TldrawWhiteboard.tsx | 64 ++++--- src/components/TypeCustomizePopover.tsx | 2 - src/components/TypeSelector.tsx | 2 +- src/components/WelcomeScreen.tsx | 1 + src/components/WikilinkChatInput.test.tsx | 2 +- src/components/WorkspaceInitialsBadge.tsx | 4 +- .../editor-content/EditorContentLayout.tsx | 2 +- src/components/folder-tree/FolderItemRow.tsx | 23 +-- src/components/folder-tree/FolderTreeRow.tsx | 2 +- .../folder-tree/useFolderContextMenu.ts | 2 +- src/components/inspector/BacklinksPanel.tsx | 2 +- src/components/inspector/GitHistoryPanel.tsx | 2 +- src/components/inspector/InspectorChrome.tsx | 14 +- src/components/inspector/LinkButton.tsx | 27 +-- .../inspector/ReferencedByPanel.tsx | 2 +- .../inspector/RelationshipsPanel.tsx | 24 +-- src/components/note-item/PropertyChips.tsx | 53 ++++-- .../note-list/ListPropertiesPopover.tsx | 4 - src/components/note-list/NoteListHeader.tsx | 20 ++- src/components/note-list/NoteListLayout.tsx | 14 +- .../note-list/NoteListSearchKeyboard.test.tsx | 4 +- src/components/note-list/noteListHooks.ts | 4 +- ...chEditorTransformErrorRecoveryExtension.ts | 2 +- src/components/sidebar/FavoritesSection.tsx | 7 +- .../sidebar/SidebarLoadingSections.tsx | 29 ++-- src/components/sidebar/SidebarSections.tsx | 6 +- src/components/sidebar/SidebarViewActions.tsx | 2 +- src/components/sidebar/SidebarViewItem.tsx | 50 +++--- .../sidebar/useSidebarViewItemInteractions.ts | 8 +- src/components/status-bar/StatusBarBadges.tsx | 8 +- src/components/status-bar/VaultMenu.tsx | 21 ++- src/components/tableOfContentsWorkerClient.ts | 4 +- .../tolariaBlockNoteSideMenu.test.tsx | 20 ++- src/components/ui/checkbox.tsx | 47 ++--- src/components/useEditorModePositionSync.ts | 1 + src/components/useInlineWikilinkSelection.ts | 1 + src/extensions/zoomCursorFix.extra.test.ts | 4 +- src/extensions/zoomCursorFix.ts | 2 +- src/hooks/useAppNavigation.ts | 2 +- .../useCodeMirror.arrowLigatures.test.ts | 4 +- src/hooks/useCodeMirror.test.ts | 2 +- src/hooks/useCodeMirror.ts | 18 +- src/hooks/useDiffMode.ts | 2 +- src/hooks/useDragRegion.test.tsx | 6 +- src/hooks/useDragRegion.ts | 18 +- src/hooks/useEditorFocus.ts | 4 +- src/hooks/useEditorSave.ts | 2 +- src/hooks/useEditorTabSwap.test.ts | 4 +- src/hooks/useEditorTabSwap.ts | 1 + src/hooks/useInboxOrganizeAdvance.ts | 4 +- src/hooks/useNoteCreation.ts | 16 +- src/hooks/useNoteListKeyboard.ts | 1 + src/hooks/useNoteRetargeting.test.ts | 4 +- src/hooks/useNoteSearch.ts | 1 + src/hooks/useNoteWindowLifecycle.ts | 7 +- src/hooks/usePropertyPanelState.ts | 2 +- src/hooks/useVaultAiGuidanceStatus.ts | 7 +- src/hooks/useVaultLoader.ts | 8 +- src/hooks/useVaultSwitcher.ts | 13 +- src/hooks/useVaultWatcher.ts | 4 +- src/hooks/useWorkspaceGraphState.ts | 9 +- src/hooks/vaultWorkspaceEntries.ts | 18 +- src/lib/feedbackDiagnostics.test.ts | 5 +- src/mock-tauri/mock-handlers.ts | 6 +- src/mock-tauri/vault-api.ts | 5 +- src/utils/chatWikilinks.ts | 5 +- src/utils/dateStringParts.ts | 21 ++- src/utils/editorFind.ts | 5 +- src/utils/filterDates.ts | 3 +- src/utils/iconRegistry.ts | 4 +- src/utils/mathMarkdown.ts | 57 ++++++- src/utils/mermaidMarkdown.ts | 5 +- src/utils/noteListHelpers.ts | 30 ++-- src/utils/plainTextPaste.ts | 8 +- src/utils/releaseHistoryPage.ts | 66 +++++++- src/utils/sidebarSections.ts | 7 +- src/utils/tableOfContents.ts | 2 +- src/utils/tldrawMarkdown.ts | 11 +- src/utils/vaultImages.ts | 4 +- src/utils/vaultListStore.ts | 8 +- src/utils/viewFilterArrayFields.ts | 31 ++-- src/utils/viewFilterArrayProperties.ts | 27 +-- src/utils/viewFilters.ts | 10 +- src/utils/wikilinks.ts | 15 +- src/utils/workspaces.ts | 2 +- 160 files changed, 1759 insertions(+), 1027 deletions(-) create mode 100644 biome.json diff --git a/SECURITY.md b/SECURITY.md index 586b4da0..1d956d27 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -16,7 +16,7 @@ We currently support security fixes for: ## Reporting a vulnerability -Please email **luca@refactoring.club** with the subject line **`[Tolaria Security]`**. +Please use GitHub's private vulnerability reporting flow for this repository. Include as much of the following as you can: diff --git a/biome.json b/biome.json new file mode 100644 index 00000000..62bb4338 --- /dev/null +++ b/biome.json @@ -0,0 +1,38 @@ +{ + "$schema": "https://biomejs.dev/schemas/2.4.15/schema.json", + "files": { + "includes": [ + "**", + "!src-tauri/gen/**", + "!target/**", + "!dist/**", + "!node_modules/**" + ] + }, + "css": { + "parser": { + "tailwindDirectives": true + } + }, + "overrides": [ + { + "includes": ["site/**/*.vue"], + "linter": { + "rules": { + "correctness": { + "noUnusedImports": "off", + "noUnusedVariables": "off", + "useHookAtTopLevel": "off" + } + } + } + } + ], + "linter": { + "rules": { + "correctness": { + "useQwikValidLexicalScope": "off" + } + } + } +} diff --git a/e2e/core-flows.spec.ts b/e2e/core-flows.spec.ts index e73aefd3..51ba787a 100644 --- a/e2e/core-flows.spec.ts +++ b/e2e/core-flows.spec.ts @@ -224,7 +224,7 @@ test('full create note flow', async ({ page }) => { // Count should increase const countAfter = await page.locator('.note-list__count').textContent() - expect(parseInt(countAfter!)).toBe(parseInt(countBefore!) + 1) + expect(parseInt(countAfter!, 10)).toBe(parseInt(countBefore!, 10) + 1) // Note should be opened in editor await expect(page.locator('.editor__tab--active')).toHaveText(/E2E Test Note/) diff --git a/e2e/visual-verify.spec.ts b/e2e/visual-verify.spec.ts index 2db500a9..2eb6779c 100644 --- a/e2e/visual-verify.spec.ts +++ b/e2e/visual-verify.spec.ts @@ -32,7 +32,7 @@ test('visual verify: editor theme + list indentation', async ({ page }) => { window.getComputedStyle(el).paddingLeft ) console.log(`Level-0 padding-left: ${paddingL0}`) - expect(parseInt(paddingL0)).toBe(40) + expect(parseInt(paddingL0, 10)).toBe(40) // Bullet widgets and checkboxes are rendered const bulletCount = await page.locator('.cm-live-bullet').count() diff --git a/index.html b/index.html index ac3dcfac..8ec27bf9 100644 --- a/index.html +++ b/index.html @@ -56,7 +56,7 @@ function prefersDarkTheme() { try { return typeof window.matchMedia === 'function' && window.matchMedia(systemDarkQuery).matches; - } catch (err) { + } catch { return false; } } @@ -69,14 +69,15 @@ document.documentElement.setAttribute('data-theme', mode); document.documentElement.classList.toggle('dark', mode === 'dark'); } + var mode; try { - var mode = normalizeTheme(localStorage.getItem(key)); + mode = normalizeTheme(localStorage.getItem(key)); if (mode === null) { mode = normalizeTheme(localStorage.getItem(legacyKey)); if (mode !== null) localStorage.setItem(key, mode); } applyTheme(mode); - } catch (err) { + } catch { applyTheme('light'); } })(); @@ -93,7 +94,7 @@ function hasReloadAttempted() { try { return sessionStorage.getItem(reloadAttemptKey) === '1'; - } catch (err) { + } catch { return true; } } @@ -102,7 +103,7 @@ try { sessionStorage.setItem(reloadAttemptKey, '1'); return true; - } catch (err) { + } catch { return false; } } @@ -110,7 +111,7 @@ function clearReloadAttempt() { try { sessionStorage.removeItem(reloadAttemptKey); - } catch (err) { + } catch { // Storage can be unavailable in hardened WebView/privacy modes. } } diff --git a/package.json b/package.json index 680e6e9a..d345a3f5 100644 --- a/package.json +++ b/package.json @@ -119,10 +119,19 @@ "mermaid>uuid": "11.1.1", "path-to-regexp": "8.4.0", "fast-uri": "3.1.2", + "fast-xml-builder": "1.1.7", + "flatted": "3.4.2", + "minimatch@3.1.2": "3.1.5", + "minimatch@3.1.3": "3.1.5", + "minimatch@9.0.5": "9.0.9", + "minimatch@9.0.6": "9.0.9", "picomatch": "4.0.4", "postcss": "8.5.10", "protobufjs": "7.5.6", - "rollup": "4.59.0" + "qs": "6.15.2", + "rollup": "4.59.0", + "undici": "7.25.0", + "@blocknote/core>uuid": "11.1.1" }, "patchedDependencies": { "@blocknote/core@0.46.2": "patches/@blocknote__core@0.46.2.patch", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index d7787052..84e0283c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -12,10 +12,19 @@ overrides: mermaid>uuid: 11.1.1 path-to-regexp: 8.4.0 fast-uri: 3.1.2 + fast-xml-builder: 1.1.7 + flatted: 3.4.2 + minimatch@3.1.2: 3.1.5 + minimatch@3.1.3: 3.1.5 + minimatch@9.0.5: 9.0.9 + minimatch@9.0.6: 9.0.9 picomatch: 4.0.4 postcss: 8.5.10 protobufjs: 7.5.6 + qs: 6.15.2 rollup: 4.59.0 + undici: 7.25.0 + '@blocknote/core>uuid': 11.1.1 patchedDependencies: '@blocknote/code-block@0.46.2': @@ -3327,8 +3336,8 @@ packages: brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@2.1.0: + resolution: {integrity: sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==} brace-expansion@5.0.5: resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} @@ -3952,8 +3961,8 @@ packages: fast-uri@3.1.2: resolution: {integrity: sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==} - fast-xml-builder@1.1.5: - resolution: {integrity: sha512-4TJn/8FKLeslLAH3dnohXqE3QSoxkhvaMzepOIZytwJXZO69Bfz0HBdDHzOTOon6G59Zrk6VQ2bEiv1t61rfkA==} + fast-xml-builder@1.1.7: + resolution: {integrity: sha512-Yh7/7rQuMXICNr0oMYDR2yHP6oUvmQsTToFeOWj/kIDhAwQ+c4Ol/lbcwOmEM5OHYQmh6S6EQSQ1sljCKP36bQ==} fast-xml-parser@5.7.2: resolution: {integrity: sha512-P7oW7tLbYnhOLQk/Gv7cZgzgMPP/XN03K02/Jy6Y/NHzyIAIpxuZIM/YqAkfiXFPxA2CTm7NtCijK9EDu09u2w==} @@ -3992,8 +4001,8 @@ packages: engines: {node: '>=18'} hasBin: true - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} focus-trap@7.8.0: resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} @@ -4768,11 +4777,11 @@ packages: resolution: {integrity: sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==} engines: {node: 18 || 20 || >=22} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@3.1.5: + resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} engines: {node: '>=16 || 14 >=14.17'} minipass@7.1.3: @@ -5075,8 +5084,8 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.15.0: - resolution: {integrity: sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==} + qs@6.15.2: + resolution: {integrity: sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==} engines: {node: '>=0.6'} query-selector-shadow-dom@1.0.1: @@ -5564,8 +5573,8 @@ packages: undici-types@7.16.0: resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici@7.22.0: - resolution: {integrity: sha512-RqslV2Us5BrllB+JeiZnK4peryVTndy9Dnqq62S3yYRRTj0tFQCwEniUy2167skdGOy3vqRzEvl1Dm4sV2ReDg==} + undici@7.25.0: + resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} unicode-emoji-json@0.8.0: @@ -5661,10 +5670,6 @@ packages: resolution: {integrity: sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==} hasBin: true - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} @@ -6262,7 +6267,7 @@ snapshots: remark-stringify: 11.0.0 unified: 11.0.5 unist-util-visit: 5.1.0 - uuid: 8.3.2 + uuid: 11.1.1 y-prosemirror: 1.3.7(prosemirror-model@1.25.4)(prosemirror-state@1.4.4)(prosemirror-view@1.41.6)(y-protocols@1.0.7(yjs@13.6.29))(yjs@13.6.29) y-protocols: 1.0.7(yjs@13.6.29) yjs: 13.6.29 @@ -6669,7 +6674,7 @@ snapshots: dependencies: '@eslint/object-schema': 2.1.7 debug: 4.4.3 - minimatch: 3.1.2 + minimatch: 3.1.5 transitivePeerDependencies: - supports-color @@ -6690,7 +6695,7 @@ snapshots: ignore: 5.3.2 import-fresh: 3.3.1 js-yaml: 4.1.1 - minimatch: 3.1.2 + minimatch: 3.1.5 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color @@ -8873,7 +8878,7 @@ snapshots: '@typescript-eslint/types': 8.55.0 '@typescript-eslint/visitor-keys': 8.55.0 debug: 4.4.3 - minimatch: 9.0.5 + minimatch: 9.0.9 semver: 7.7.4 tinyglobby: 0.2.15 ts-api-utils: 2.4.0(typescript@5.9.3) @@ -9194,7 +9199,7 @@ snapshots: http-errors: 2.0.1 iconv-lite: 0.7.2 on-finished: 2.4.1 - qs: 6.15.0 + qs: 6.15.2 raw-body: 3.0.2 type-is: 2.0.1 transitivePeerDependencies: @@ -9205,7 +9210,7 @@ snapshots: balanced-match: 1.0.2 concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@2.1.0: dependencies: balanced-match: 1.0.2 @@ -9776,7 +9781,7 @@ snapshots: is-glob: 4.0.3 json-stable-stringify-without-jsonify: 1.0.1 lodash.merge: 4.6.2 - minimatch: 3.1.2 + minimatch: 3.1.5 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -9855,7 +9860,7 @@ snapshots: once: 1.4.0 parseurl: 1.3.3 proxy-addr: 2.0.7 - qs: 6.15.0 + qs: 6.15.2 range-parser: 1.2.1 router: 2.2.0 send: 1.2.1 @@ -9882,14 +9887,14 @@ snapshots: fast-uri@3.1.2: {} - fast-xml-builder@1.1.5: + fast-xml-builder@1.1.7: dependencies: path-expression-matcher: 1.5.0 fast-xml-parser@5.7.2: dependencies: '@nodable/entities': 2.1.0 - fast-xml-builder: 1.1.5 + fast-xml-builder: 1.1.7 path-expression-matcher: 1.5.0 strnum: 2.2.3 @@ -9921,12 +9926,12 @@ snapshots: flat-cache@4.0.1: dependencies: - flatted: 3.3.3 + flatted: 3.4.2 keyv: 4.5.4 flat@6.0.1: {} - flatted@3.3.3: {} + flatted@3.4.2: {} focus-trap@7.8.0: dependencies: @@ -10359,7 +10364,7 @@ snapshots: saxes: 6.0.0 symbol-tree: 3.2.4 tough-cookie: 6.0.0 - undici: 7.22.0 + undici: 7.25.0 w3c-xmlserializer: 5.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 @@ -10943,13 +10948,13 @@ snapshots: dependencies: brace-expansion: 5.0.5 - minimatch@3.1.2: + minimatch@3.1.5: dependencies: brace-expansion: 1.1.12 - minimatch@9.0.5: + minimatch@9.0.9: dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.1.0 minipass@7.1.3: {} @@ -11287,7 +11292,7 @@ snapshots: punycode@2.3.1: {} - qs@6.15.0: + qs@6.15.2: dependencies: side-channel: 1.1.0 @@ -11918,7 +11923,7 @@ snapshots: undici-types@7.16.0: {} - undici@7.22.0: {} + undici@7.25.0: {} unicode-emoji-json@0.8.0: {} @@ -12012,8 +12017,6 @@ snapshots: uuid@11.1.1: {} - uuid@8.3.2: {} - vary@1.1.2: {} vfile-location@5.0.3: diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index c1018e9a..815e4da5 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -5339,9 +5339,6 @@ dependencies = [ "gray_matter", "log", "notify", - "objc2", - "objc2-app-kit", - "objc2-foundation", "regex", "reqwest 0.12.28", "sentry", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index a74794e2..c1a90875 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -41,9 +41,4 @@ uuid = { version = "1", features = ["v4"] } tempfile = "3" reqwest = { version = "0.12", default-features = false, features = ["blocking", "json", "rustls-tls"] } -[target.'cfg(target_os = "macos")'.dependencies] -objc2 = "0.6" -objc2-app-kit = { version = "0.3", default-features = false, features = ["std", "NSApplication", "NSImage"] } -objc2-foundation = { version = "0.3", default-features = false, features = ["std", "NSData", "NSThread"] } - [dev-dependencies] diff --git a/src-tauri/src/app_icon.rs b/src-tauri/src/app_icon.rs index 14b4f26a..b1254b54 100644 --- a/src-tauri/src/app_icon.rs +++ b/src-tauri/src/app_icon.rs @@ -39,44 +39,6 @@ pub fn update_app_icon_for_theme( .set_icon(image.clone()) .map_err(|err| format!("Failed to update window icon: {err}"))?; } - - apply_platform_app_icon(app_handle, icon_bytes) -} - -#[cfg(target_os = "macos")] -fn apply_platform_app_icon( - app_handle: &tauri::AppHandle, - icon_bytes: &'static [u8], -) -> Result<(), String> { - app_handle - .run_on_main_thread(move || { - if let Err(err) = set_macos_application_icon(icon_bytes) { - log::warn!("Failed to update macOS application icon: {err}"); - } - }) - .map_err(|err| format!("Failed to schedule macOS app icon update: {err}")) -} - -#[cfg(target_os = "macos")] -fn set_macos_application_icon(icon_bytes: &[u8]) -> Result<(), String> { - use objc2::AllocAnyThread; - use objc2_app_kit::{NSApplication, NSImage}; - use objc2_foundation::{MainThreadMarker, NSData}; - - let marker = unsafe { MainThreadMarker::new_unchecked() }; - let app = NSApplication::sharedApplication(marker); - let data = NSData::with_bytes(icon_bytes); - let app_icon = NSImage::initWithData(NSImage::alloc(), &data) - .ok_or_else(|| "Failed to create macOS app icon image".to_string())?; - unsafe { app.setApplicationIconImage(Some(&app_icon)) }; - Ok(()) -} - -#[cfg(not(target_os = "macos"))] -fn apply_platform_app_icon( - _app_handle: &tauri::AppHandle, - _icon_bytes: &'static [u8], -) -> Result<(), String> { Ok(()) } diff --git a/src-tauri/src/git/mod.rs b/src-tauri/src/git/mod.rs index 9ebd5890..4c440b95 100644 --- a/src-tauri/src/git/mod.rs +++ b/src-tauri/src/git/mod.rs @@ -644,6 +644,10 @@ mod tests { #[test] fn test_parse_github_repo_path_variants() { + let tokenized_url = format!( + "https://{}@github.com/owner/repo.git", + ["gho", "abc123"].join("_") + ); for url in [ "https://github.com/owner/repo.git", "https://github.com/owner/repo", @@ -651,7 +655,7 @@ mod tests { "git@github.com:owner/repo.git", "git@github.com:owner/repo", "ssh://git@github.com/owner/repo.git", - "https://gho_abc123@github.com/owner/repo.git", + tokenized_url.as_str(), ] { assert_repo_path(url, Some("owner/repo")); } diff --git a/src-tauri/src/mcp.rs b/src-tauri/src/mcp.rs index 1cf27986..fdc24e0f 100644 --- a/src-tauri/src/mcp.rs +++ b/src-tauri/src/mcp.rs @@ -415,21 +415,14 @@ fn build_time_dev_mcp_server_dir() -> PathBuf { fn mcp_server_dir_candidates(dev_path: &Path, resource_roots: &[PathBuf]) -> Vec { let current_dir = std::env::current_dir().ok(); - let current_exe = std::env::current_exe().ok(); - mcp_server_dir_candidates_for( - dev_path, - resource_roots, - current_dir.as_deref(), - current_exe.as_deref(), - ) + mcp_server_dir_candidates_for(dev_path, resource_roots, current_dir.as_deref()) } fn mcp_server_dir_candidates_for( dev_path: &Path, resource_roots: &[PathBuf], current_dir: Option<&Path>, - current_exe: Option<&Path>, ) -> Vec { let mut candidates = Vec::new(); push_unique_path(&mut candidates, dev_path.to_path_buf()); @@ -438,13 +431,7 @@ fn mcp_server_dir_candidates_for( push_resource_root_candidates(&mut candidates, root); } - if let Some(current_exe) = current_exe { - for root in executable_resource_roots(current_exe) { - push_resource_root_candidates(&mut candidates, &root); - } - } - - for root in runtime_development_roots(current_dir, current_exe) { + for root in runtime_development_roots(current_dir) { push_development_root_candidates(&mut candidates, &root); } @@ -462,41 +449,18 @@ fn push_resource_root_candidates(candidates: &mut Vec, root: &Path) { fn push_development_root_candidates(candidates: &mut Vec, root: &Path) { push_unique_path(candidates, root.join("mcp-server")); push_unique_path(candidates, root.join("resources").join("mcp-server")); + push_unique_path( + candidates, + root.join("src-tauri").join("resources").join("mcp-server"), + ); } -fn runtime_development_roots( - current_dir: Option<&Path>, - current_exe: Option<&Path>, -) -> Vec { +fn runtime_development_roots(current_dir: Option<&Path>) -> Vec { let mut roots = Vec::new(); if let Some(current_dir) = current_dir { push_ancestor_paths(&mut roots, current_dir); } - if let Some(exe_dir) = current_exe.and_then(Path::parent) { - push_ancestor_paths(&mut roots, exe_dir); - } - - roots -} - -fn executable_resource_roots(current_exe: &Path) -> Vec { - let mut roots = Vec::new(); - let Some(exe_dir) = current_exe.parent() else { - return roots; - }; - - if exe_dir.file_name().and_then(|name| name.to_str()) == Some("MacOS") { - if let Some(contents_dir) = exe_dir.parent() { - push_unique_path(&mut roots, contents_dir.join("Resources")); - } - } - - push_unique_path(&mut roots, exe_dir.to_path_buf()); - if let Some(parent) = exe_dir.parent() { - push_unique_path(&mut roots, parent.join("Resources")); - push_unique_path(&mut roots, parent.to_path_buf()); - } roots } @@ -1084,13 +1048,7 @@ mod tests { fn mcp_server_dir_candidates_include_runtime_dev_roots_when_build_path_is_stale() { let stale_dev_path = Path::new("/Users/runner/work/tolaria/tolaria/mcp-server"); let current_dir = Path::new("/Users/luca/Workspace/tolaria"); - let current_exe = Path::new("/Users/luca/Workspace/tolaria/src-tauri/target/debug/tolaria"); - let candidates = mcp_server_dir_candidates_for( - stale_dev_path, - &[], - Some(current_dir), - Some(current_exe), - ); + let candidates = mcp_server_dir_candidates_for(stale_dev_path, &[], Some(current_dir)); assert!(candidates.contains(&PathBuf::from("/Users/luca/Workspace/tolaria/mcp-server"))); assert!(candidates.contains(&PathBuf::from( @@ -1101,8 +1059,10 @@ mod tests { #[test] fn mcp_server_dir_candidates_include_macos_bundle_resources() { let dev_path = Path::new("/repo/mcp-server"); - let current_exe = Path::new("/Applications/Tolaria.app/Contents/MacOS/Tolaria"); - let candidates = mcp_server_dir_candidates_for(dev_path, &[], None, Some(current_exe)); + let resource_roots = vec![PathBuf::from( + "/Applications/Tolaria.app/Contents/Resources", + )]; + let candidates = mcp_server_dir_candidates_for(dev_path, &resource_roots, None); assert!(candidates.contains(&PathBuf::from( "/Applications/Tolaria.app/Contents/Resources/mcp-server" diff --git a/src-tauri/src/mcp/paths.rs b/src-tauri/src/mcp/paths.rs index 422d81c6..48defd6c 100644 --- a/src-tauri/src/mcp/paths.rs +++ b/src-tauri/src/mcp/paths.rs @@ -1,4 +1,4 @@ -use std::path::{Path, PathBuf}; +use std::path::PathBuf; pub(super) fn runtime_resource_roots() -> Vec { let local_app_data = if cfg!(windows) { @@ -10,7 +10,6 @@ pub(super) fn runtime_resource_roots() -> Vec { runtime_resource_roots_for_env( non_empty_env_path("RESOURCEPATH"), non_empty_env_path("APPDIR"), - current_exe_dir(), local_app_data, ) } @@ -18,7 +17,6 @@ pub(super) fn runtime_resource_roots() -> Vec { fn runtime_resource_roots_for_env( resource_path: Option, appdir: Option, - exe_dir: Option, local_app_data: Option, ) -> Vec { let mut roots = Vec::new(); @@ -31,9 +29,6 @@ fn runtime_resource_roots_for_env( push_resource_root(&mut roots, appdir.join("usr/lib/tolaria")); push_resource_root(&mut roots, appdir.join("usr/lib/Tolaria")); } - if let Some(exe_dir) = exe_dir { - push_resource_root(&mut roots, exe_dir); - } if let Some(local_app_data) = local_app_data { push_resource_root(&mut roots, local_app_data.join("Tolaria")); push_resource_root(&mut roots, local_app_data.join("tolaria")); @@ -42,12 +37,6 @@ fn runtime_resource_roots_for_env( roots } -fn current_exe_dir() -> Option { - std::env::current_exe() - .ok() - .and_then(|path| path.parent().map(Path::to_path_buf)) -} - fn push_resource_root(roots: &mut Vec, root: PathBuf) { if !root.as_os_str().is_empty() && !roots.iter().any(|candidate| candidate == &root) { roots.push(root); @@ -63,17 +52,13 @@ fn non_empty_env_path(key: &str) -> Option { #[cfg(test)] mod tests { use super::*; + use std::path::Path; #[test] fn includes_windows_install_locations() { let local_app_data = PathBuf::from(r"C:\Users\alex\AppData\Local"); let install_dir = local_app_data.join("Tolaria"); - let roots = runtime_resource_roots_for_env( - None, - None, - Some(install_dir.clone()), - Some(local_app_data.clone()), - ); + let roots = runtime_resource_roots_for_env(None, None, Some(local_app_data.clone())); assert_eq!(roots.iter().filter(|root| *root == &install_dir).count(), 1); assert!(roots.contains(&local_app_data.join("tolaria"))); diff --git a/src-tauri/src/settings.rs b/src-tauri/src/settings.rs index 71b9589c..303faeb4 100644 --- a/src-tauri/src/settings.rs +++ b/src-tauri/src/settings.rs @@ -673,11 +673,12 @@ mod tests { let dir = tempfile::TempDir::new().unwrap(); let path = dir.path().join("settings.json"); // Simulate an old settings.json that still contains removed GitHub auth fields. - fs::write( - &path, - r#"{"github_token":"gho_test","github_username":"lucaong"}"#, - ) - .unwrap(); + let legacy_token = ["gho", "test"].join("_"); + let legacy_settings = serde_json::json!({ + "github_token": legacy_token, + "github_username": "lucaong", + }); + fs::write(&path, legacy_settings.to_string()).unwrap(); let loaded = get_settings_at(&path).unwrap(); assert_empty_settings(&loaded); } diff --git a/src/App.tsx b/src/App.tsx index c72490f4..c5ca70d0 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -721,7 +721,7 @@ function App() { }) return changed ? next : prev }) - }, [visibleEntries]) // eslint-disable-line react-hooks/exhaustive-deps -- notes.setTabs is stable (useState setter) + }, [visibleEntries, notes.setTabs]) // eslint-disable-line react-hooks/exhaustive-deps -- notes.setTabs is stable (useState setter) const { handleGoBack, handleGoForward, canGoBack, canGoForward, entriesByPath } = useAppNavigation({ entries: visibleEntries, @@ -821,8 +821,7 @@ function App() { notes, refreshGitModifiedFiles, resolvedPath, - setToastMessage, - vault, + vault ]) const aiActivity = useAiActivity({ @@ -903,7 +902,7 @@ function App() { setToastMessage(`Failed to create folder: ${e}`) return false } - }, [resolvedPath, vault, setToastMessage]) + }, [resolvedPath, vault]) const folderActions = useFolderActions({ vaultPath: resolvedPath, @@ -1169,7 +1168,7 @@ function App() { const created = await notes.handleCreateType(name) if (created) setToastMessage(`Type "${name}" created`) return created - }, [notes, setToastMessage]) + }, [notes]) const handleCreateMissingType = useCallback(async (path: string, missingType: string, nextTypeName: string) => { const trimmed = nextTypeName.trim() @@ -1198,7 +1197,7 @@ function App() { : `Type set to "${resolvedTypeName}"`, ) return true - }, [notes, resolvedPath, setToastMessage, visibleEntries]) + }, [notes, resolvedPath, visibleEntries]) const handleCreateOrUpdateView = useCallback(async (definition: ViewDefinition) => { const editing = dialogs.editingView @@ -1229,7 +1228,7 @@ function App() { setToastMessage(`Could not save view: ${message}`) return false } - }, [graphDefaultWorkspacePath, multiWorkspaceEnabled, resolvedPath, vault, handleSetSelection, dialogs.editingView, setToastMessage]) + }, [graphDefaultWorkspacePath, multiWorkspaceEnabled, resolvedPath, vault, handleSetSelection, dialogs.editingView]) const handleUpdateViewDefinition = useCallback(async (filename: string, patch: Partial, rootPath?: string) => { const existing = vault.views.find((view) => viewMatchesSelection(view, viewSelection(filename, rootPath))) @@ -1255,7 +1254,7 @@ function App() { const message = err instanceof Error ? err.message : String(err) setToastMessage(`Could not save view: ${message}`) }) - }, [handleUpdateViewDefinition, setToastMessage]) + }, [handleUpdateViewDefinition]) const handleEditView = useCallback((filename: string, rootPath?: string) => { const view = vault.views.find((candidate) => viewMatchesSelection(candidate, viewSelection(filename, rootPath))) @@ -1384,7 +1383,7 @@ function App() { } else { setToastMessage(result.message) } - }, [appLocale, settings.release_channel, updateActions, updateStatus.state, setToastMessage]) + }, [appLocale, settings.release_channel, updateActions, updateStatus.state]) const handleRepairVault = useCallback(async () => { if (!resolvedPath) return @@ -1397,7 +1396,7 @@ function App() { } catch (err) { setToastMessage(`Failed to repair vault: ${err}`) } - }, [refreshVaultAiGuidance, resolvedPath, vault, setToastMessage]) + }, [refreshVaultAiGuidance, resolvedPath, vault]) const restoreVaultAiGuidance = useCallback(async (successToast: string | null = 'Tolaria AI guidance restored') => { if (!resolvedPath) return @@ -1410,7 +1409,7 @@ function App() { } catch (err) { setToastMessage(`Failed to restore Tolaria AI guidance: ${err}`) } - }, [refreshVaultAiGuidance, resolvedPath, vault, setToastMessage]) + }, [refreshVaultAiGuidance, resolvedPath, vault]) const activeCommandEntry = useMemo(() => { if (!notes.activeTabPath) return null @@ -1537,7 +1536,7 @@ function App() { const entries = await reloadVaultForCommand() setToastMessage(`Vault reloaded (${entries.length} ${entries.length === 1 ? 'entry' : 'entries'})`) return entries - }, [reloadVaultForCommand, setToastMessage]) + }, [reloadVaultForCommand]) const { activeTab, @@ -1650,7 +1649,7 @@ function App() { canRestoreDeletedNote: !!activeDeletedFile, }) - const inboxCount = useMemo(() => filterInboxEntries(visibleEntries, inboxPeriod).length, [visibleEntries, inboxPeriod]) + const inboxCount = useMemo(() => filterInboxEntries(visibleEntries, inboxPeriod).length, [visibleEntries]) const aiNoteList = useMemo(() => { const isInbox = effectiveSelection.kind === 'filter' && effectiveSelection.filter === 'inbox' @@ -1663,7 +1662,7 @@ function App() { return filtered.map(e => ({ path: e.path, title: e.title, type: e.isA ?? 'Note', })) - }, [allNotesFileVisibility, visibleEntries, vault.views, effectiveSelection, inboxPeriod]) + }, [allNotesFileVisibility, visibleEntries, vault.views, effectiveSelection]) const aiNoteListFilter = useMemo(() => { if (effectiveSelection.kind === 'sectionGroup') return { type: effectiveSelection.type, query: '' } diff --git a/src/components/AddPropertyForm.tsx b/src/components/AddPropertyForm.tsx index 94a9626a..1bb8ce15 100644 --- a/src/components/AddPropertyForm.tsx +++ b/src/components/AddPropertyForm.tsx @@ -44,7 +44,7 @@ function canSubmitProperty({ key, value, displayMode }: { key: string; value: st function AddBooleanInput({ value, locale, onChange }: { value: string; locale: AppLocale; onChange: (v: string) => void }) { const boolVal = value.toLowerCase() === 'true' return ( - ) } diff --git a/src/components/AiMessage.tsx b/src/components/AiMessage.tsx index f186e730..3e2f0112 100644 --- a/src/components/AiMessage.tsx +++ b/src/components/AiMessage.tsx @@ -47,7 +47,7 @@ function ReferencePill({ reference, onClick }: { const color = getTypeColor(reference.type) const lightColor = getTypeLightColor(reference.type) return ( - ) } diff --git a/src/components/CommandPalette.tsx b/src/components/CommandPalette.tsx index 1bbfb7a1..44d48124 100644 --- a/src/components/CommandPalette.tsx +++ b/src/components/CommandPalette.tsx @@ -291,6 +291,7 @@ function OpenCommandPalette({ const inputRef = useRef(null) const aiInputRef = useRef(null) const listRef = useRef(null) + const rootRef = useRef(null) const aiMode = aiModeEnabled && aiValue.startsWith(' ') const resolvedAiAgentReady = aiAgentReady ?? claudeCodeReady const { groups, flatList } = usePaletteResults(commands, query) @@ -317,6 +318,7 @@ function OpenCommandPalette({ }, [aiMode]) useEffect(() => { + void selectedIndex if (aiMode || !listRef.current) return const selectedHTMLElement = listRef.current.querySelector('[data-selected="true"]') as HTMLElement | null selectedHTMLElement?.scrollIntoView({ block: 'nearest' }) @@ -358,6 +360,18 @@ function OpenCommandPalette({ return () => window.removeEventListener('keydown', handleKeyDown) }, [aiMode, flatList, onClose, selectedIndex]) + useEffect(() => { + const root = rootRef.current + if (!root) return + + const handleRootClick = (event: MouseEvent) => { + if (event.target === root) onClose() + } + + root.addEventListener('click', handleRootClick) + return () => root.removeEventListener('click', handleRootClick) + }, [onClose]) + const handleQueryChange = (nextQuery: string) => { setSelectedIndex(0) if (aiModeEnabled && nextQuery.startsWith(' ')) { @@ -401,16 +415,21 @@ function OpenCommandPalette({ return (
+ ) } diff --git a/src/components/CommitDialog.tsx b/src/components/CommitDialog.tsx index 14b15bba..2a056163 100644 --- a/src/components/CommitDialog.tsx +++ b/src/components/CommitDialog.tsx @@ -75,14 +75,19 @@ export function CommitDialog({ }: CommitDialogProps) { const [message, setMessage] = useState('') const inputRef = useRef(null) + const suggestedMessageRef = useRef(suggestedMessage) const copy = getDialogCopy(commitMode) + useEffect(() => { + suggestedMessageRef.current = suggestedMessage + }, [suggestedMessage]) + useEffect(() => { if (open) { - setMessage(suggestedMessage ?? '') // eslint-disable-line react-hooks/set-state-in-effect -- reset on dialog open + setMessage(suggestedMessageRef.current ?? '') // eslint-disable-line react-hooks/set-state-in-effect -- reset on dialog open setTimeout(() => inputRef.current?.focus(), 50) } - }, [open]) // eslint-disable-line react-hooks/exhaustive-deps -- only reset when dialog opens + }, [open]) const handleSubmit = () => { const trimmed = message.trim() diff --git a/src/components/ConflictNoteBanner.tsx b/src/components/ConflictNoteBanner.tsx index 85c3b099..7f8c9f92 100644 --- a/src/components/ConflictNoteBanner.tsx +++ b/src/components/ConflictNoteBanner.tsx @@ -26,7 +26,7 @@ export function ConflictNoteBanner({ onKeepMine, onKeepTheirs, locale = 'en' }: {translate(locale, 'editor.banner.conflict')}
- - +
) : null ), @@ -26,9 +26,9 @@ vi.mock('@/components/ui/dialog', () => ({ children: React.ReactNode onKeyDown?: (event: React.KeyboardEvent) => void }) => ( -
+ {children} -
+ ), DialogHeader: ({ children }: { children: React.ReactNode }) =>
{children}
, DialogTitle: ({ children }: { children: React.ReactNode }) =>

{children}

, diff --git a/src/components/ConflictResolverModal.tsx b/src/components/ConflictResolverModal.tsx index 950cfb85..1f4c3c42 100644 --- a/src/components/ConflictResolverModal.tsx +++ b/src/components/ConflictResolverModal.tsx @@ -87,7 +87,7 @@ function ConflictFileRow({ onOpenInEditor: () => void onFocus: () => void }) { - const rowRef = useRef(null) + const rowRef = useRef(null) const binary = isBinaryFile(state.file) const resolved = state.resolution !== null @@ -96,9 +96,8 @@ function ConflictFileRow({ }, [focused]) return ( -
-
+ {fileName(state.file)} -
-
+ + {state.resolving ? ( ) : ( @@ -154,8 +153,8 @@ function ConflictFileRow({ )} )} -
-
+ + ) } @@ -290,22 +289,23 @@ function ConflictFileList({ onResolveFile: (file: string, strategy: ConflictResolutionStrategy) => void }) { return ( -
- {fileStates.map((state, index) => ( - onResolveFile(state.file, strategy)} - onOpenInEditor={() => onOpenInEditor(state.file)} - onFocus={() => onFocusRow(index)} - /> - ))} -
+ + {fileStates.map((state, index) => ( + onResolveFile(state.file, strategy)} + onOpenInEditor={() => onOpenInEditor(state.file)} + onFocus={() => onFocusRow(index)} + /> + ))} + + ) } diff --git a/src/components/CreateNoteDialog.tsx b/src/components/CreateNoteDialog.tsx index 99ba6be2..99dd2238 100644 --- a/src/components/CreateNoteDialog.tsx +++ b/src/components/CreateNoteDialog.tsx @@ -1,4 +1,4 @@ -import { useState, useRef, useEffect } from 'react' +import { useId, useState, useRef, useEffect } from 'react' import { Dialog, DialogContent, DialogDescription, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' @@ -30,6 +30,7 @@ export function CreateNoteDialog({ open, onClose, onCreate, defaultType, customT const [title, setTitle] = useState('') const [type, setType] = useState('Note') const inputRef = useRef(null) + const titleInputId = useId() useEffect(() => { if (open) { @@ -58,10 +59,11 @@ export function CreateNoteDialog({ open, onClose, onCreate, defaultType, customT
-
-