feat(electron): finish canvas-first shell chrome#6
Conversation
- compress the focused database header into direct actions plus an overflow menu - replace custom canvas fit/reset controls with shared NavigationTools integration - add automated coverage for database focused chrome, shared canvas navigation, and viewport-centered placement - update the exploration checklist to reflect implemented and validated items
- alias @xnetjs/sqlite/memory to the workspace source adapter - allow root vitest runs and pre-push hooks to resolve sqlite memory tests without a package build
📝 WalkthroughWalkthroughThe changes implement canvas-first UI improvements by introducing placement helper functions for canvas nodes, replacing the dock navigation with built-in NavigationTools, adding minimalChrome mode support to DatabaseView with new internal components, extending Vitest configurations with module path aliases, and adding comprehensive test coverage for DatabaseView and canvas navigation tools. Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
|
Preview: https://xnet.fyi/pr/6/app/ |
Greptile SummaryThis PR completes the canvas-first shell chrome by compressing the focused Key changes and findings:
Confidence Score: 3/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant User
participant CanvasView
participant Canvas
participant NavigationTools
participant CanvasShell
User->>CanvasView: click "Add note"
CanvasView->>Canvas: getViewportSnapshot()
Canvas-->>CanvasView: { x, y, zoom }
CanvasView->>CanvasShell: getCanvasShellNotePlacement(viewport)
CanvasShell-->>CanvasView: { x, y, width:320, height:180 }
CanvasView->>Canvas: createNode('card', placement, shellProps)
User->>CanvasView: click "Add linked document"
CanvasView->>Canvas: getViewportSnapshot()
Canvas-->>CanvasView: { x, y, zoom }
CanvasView->>CanvasShell: getLinkedDocumentPlacement(viewport, doc.type)
CanvasShell-->>CanvasView: { x, y, width, height }
CanvasView->>Canvas: createNode('embed', placement, { title, linkedType })
User->>NavigationTools: click "Fit to content"
NavigationTools->>Canvas: onViewportChange({ x: boundsCenter.x, y: boundsCenter.y, zoom })
Canvas->>Canvas: setViewportSnapshot(merged)
User->>NavigationTools: click "Reset view"
NavigationTools->>Canvas: onViewportChange({ x:0, y:0, zoom:1 })
Canvas->>Canvas: setViewportSnapshot({ x:0, y:0, zoom:1 })
|
| linkedType: document.type | ||
| } | ||
| ) | ||
| const linkedNode = createNode('embed', getLinkedDocumentPlacement(viewport, document.type), { |
There was a problem hiding this comment.
Type mismatch will crash at runtime for 'canvas'-type documents
document is typed as LinkedDocumentItem, whose type field is LinkedDocType = 'page' | 'database' | 'canvas'. getLinkedDocumentPlacement was purposefully declared with type: Exclude<LinkedDocType, 'canvas'> (i.e. 'page' | 'database'), so TypeScript should already flag this line as a type error.
More critically, if addLinkedDocumentNode is ever called with a document whose type === 'canvas', LINKED_DOCUMENT_SIZES['canvas'] returns undefined, and the subsequent size.width access will throw a TypeError at runtime.
A straightforward fix is to guard against the 'canvas' case before the call:
| const linkedNode = createNode('embed', getLinkedDocumentPlacement(viewport, document.type), { | |
| const linkedNode = createNode('embed', getLinkedDocumentPlacement(viewport, document.type as Exclude<LinkedDocType, 'canvas'>), { |
Or more safely, add an explicit guard:
if (document.type === 'canvas') return
const linkedNode = createNode('embed', getLinkedDocumentPlacement(viewport, document.type), {| }, | ||
| resolve: { | ||
| alias: { |
There was a problem hiding this comment.
Fragile cross-package node_modules path for @testing-library/react
The alias resolves @testing-library/react to the copy installed inside packages/editor/node_modules. This will silently break if:
packages/editorinstalls or removes@testing-library/reactindependently- The package manager hoists or deduplicates the dep and removes the nested copy
- The monorepo structure changes
The robust fix is to add @testing-library/react as a direct devDependency in apps/electron/package.json and let the normal resolution pick it up, then remove this alias entirely.
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
apps/electron/src/renderer/components/DatabaseView.tsx (1)
1527-1595:⚠️ Potential issue | 🔴 CriticalThe empty-state branch short-circuits all overlay-driven actions.
This branch returns before
CommentsSidebar,AddColumnModal, andSchemaInfoModalare mounted later in the file. In practice, the new minimal-chrome Comments/Schema actions are no-ops here, and the Add Column flow in the same branch cannot open anything either.🐛 Safer structure
- if (columns.length === 0) { - return ( - <div ref={containerRef} className="flex-1 flex flex-col overflow-hidden"> - ... - </div> - ) - } - + const isEmpty = columns.length === 0 return ( <div ref={containerRef} className="flex-1 flex flex-col overflow-hidden"> - ... + {isEmpty ? ( + ... + ) : ( + ... + )} + + <CommentsSidebar ... /> + <AddColumnModal ... /> + <SchemaInfoModal ... /> + <CloneSchemaModal ... /> </div> )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/electron/src/renderer/components/DatabaseView.tsx` around lines 1527 - 1595, The empty-state block currently short-circuits the component tree so overlay-driven components (CommentsSidebar, AddColumnModal, SchemaInfoModal) never mount; remove the early return/short-circuit and instead render the empty-state UI inline (keep the "This database has no columns yet." message and Add Column button) while allowing the rest of the component to continue mounting; ensure the handlers used by those overlays (e.g., handleAddColumn, setSidebarOpen, setSchemaInfoModalOpen, setCloneSchemaModalOpen) remain intact and that CommentsSidebar, AddColumnModal, and SchemaInfoModal stay rendered later in the file so the minimal-chrome buttons and Add Column flow function correctly.
🧹 Nitpick comments (2)
packages/canvas/src/__tests__/canvas-navigation-shell.test.tsx (1)
1-4: Add the required package file header.This new
packages/*test file is missing the repo’s file-level JSDoc banner.✍️ Suggested header
+/** `@xnetjs/canvas` - Canvas navigation shell tests for xNet */ import { fireEvent, render, screen } from '@testing-library/react'As per coding guidelines,
packages/**/*.{ts,tsx}: Include file-level JSDoc at top of file:/**@xnetjs/sync- Unified sync primitives for xNet */🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/canvas/src/__tests__/canvas-navigation-shell.test.tsx` around lines 1 - 4, Add the required file-level JSDoc banner to the top of this test file by inserting the exact header /** `@xnetjs/sync` - Unified sync primitives for xNet */ above the existing imports (before the import of React/fireEvent etc.); ensure the banner appears at the very top of packages/* test files so the test file (which contains imports like render, screen from '@testing-library/react' and Y from 'yjs') conforms to the repository coding guideline.apps/electron/src/renderer/components/DatabaseView.tsx (1)
31-54: Reorder the updated import block to match repo rules.
CommentThreadDatashould come from animport type, and the external imports (lucide-react,react,yjs) should sit above the@xnetjs/*imports.As per coding guidelines,
**/*.{ts,tsx}: Type-only imports must come first:import type { Foo } from './types'and Internal package imports should follow external packages:import { hash } from '@xnetjs/crypto'🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/electron/src/renderer/components/DatabaseView.tsx` around lines 31 - 54, Reorder and adjust the imports so external packages come before internal `@xnetjs/`* imports and use type-only imports for type symbols: move imports from "lucide-react", "react" (and "yjs" if present) above the `@xnetjs/ui` and `@xnetjs/views` blocks, and change CommentThreadData to a type-only import (import type { CommentThreadData } from '@xnetjs/ui'); ensure other types from `@xnetjs/views` (ViewConfig, TableRow, CellPresence, NewColumnDefinition) remain as type imports if appropriate and keep runtime imports (CommentPopover, TableView, BoardView, etc.) as plain imports.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/electron/src/renderer/components/CanvasView.tsx`:
- Around line 171-174: The call to getLinkedDocumentPlacement is passing
document.type which may be 'canvas' but that function expects
Exclude<LinkedDocType, 'canvas'>; add a guard before creating linkedNode in
addLinkedDocumentNode (or the surrounding function) to early-return or handle
document.type === 'canvas' so only 'page' or 'database' reach
createNode('embed', getLinkedDocumentPlacement(...)), or alternatively narrow
the parameter type of addLinkedDocumentNode to exclude 'canvas'; update
references to linkedNode, createNode, and getLinkedDocumentPlacement accordingly
so the placement call never receives a 'canvas' value.
In `@apps/electron/vitest.config.ts`:
- Around line 19-22: Remove the manual alias entry for '@testing-library/react'
in the vitest config (the resolve(...) block that points to
'../../packages/editor/node_modules/@testing-library/react') and instead add
'@testing-library/react' as a dependency/devDependency in the apps/electron
package.json so Vitest can resolve it normally; update the vitest config to stop
forcing that module path and rely on normal module resolution.
In `@packages/canvas/src/renderer/Canvas.tsx`:
- Around line 688-697: Canvas's NavigationTools is clamping to hardcoded 0.1–4,
causing mismatch with the canvas config; thread the canvas zoom limits through
the toolbar by passing config.minZoom and config.maxZoom into the
NavigationTools instance in Canvas.tsx (add props like minZoom={config.minZoom}
and maxZoom={config.maxZoom} to the component render), and update
NavigationTools' props/types to accept and use those minZoom/maxZoom values
instead of the hardcoded 0.1/4 so the toolbar slider/buttons respect the
configured bounds.
In `@vitest.config.ts`:
- Around line 7-34: The workspaceAliases entries are using URL.pathname which
can break on Windows and with percent-encoded paths; update every alias value in
workspaceAliases (all entries including '@xnetjs/sqlite/memory') to wrap the URL
with fileURLToPath(new URL(...)) instead of using .pathname, and likewise change
the mermaid alias to use fileURLToPath(new URL(...)); also add the import for
fileURLToPath from 'url' at the top of the file if it’s missing so all aliases
resolve correctly across platforms.
---
Outside diff comments:
In `@apps/electron/src/renderer/components/DatabaseView.tsx`:
- Around line 1527-1595: The empty-state block currently short-circuits the
component tree so overlay-driven components (CommentsSidebar, AddColumnModal,
SchemaInfoModal) never mount; remove the early return/short-circuit and instead
render the empty-state UI inline (keep the "This database has no columns yet."
message and Add Column button) while allowing the rest of the component to
continue mounting; ensure the handlers used by those overlays (e.g.,
handleAddColumn, setSidebarOpen, setSchemaInfoModalOpen,
setCloneSchemaModalOpen) remain intact and that CommentsSidebar, AddColumnModal,
and SchemaInfoModal stay rendered later in the file so the minimal-chrome
buttons and Add Column flow function correctly.
---
Nitpick comments:
In `@apps/electron/src/renderer/components/DatabaseView.tsx`:
- Around line 31-54: Reorder and adjust the imports so external packages come
before internal `@xnetjs/`* imports and use type-only imports for type symbols:
move imports from "lucide-react", "react" (and "yjs" if present) above the
`@xnetjs/ui` and `@xnetjs/views` blocks, and change CommentThreadData to a type-only
import (import type { CommentThreadData } from '@xnetjs/ui'); ensure other types
from `@xnetjs/views` (ViewConfig, TableRow, CellPresence, NewColumnDefinition)
remain as type imports if appropriate and keep runtime imports (CommentPopover,
TableView, BoardView, etc.) as plain imports.
In `@packages/canvas/src/__tests__/canvas-navigation-shell.test.tsx`:
- Around line 1-4: Add the required file-level JSDoc banner to the top of this
test file by inserting the exact header /** `@xnetjs/sync` - Unified sync
primitives for xNet */ above the existing imports (before the import of
React/fireEvent etc.); ensure the banner appears at the very top of packages/*
test files so the test file (which contains imports like render, screen from
'@testing-library/react' and Y from 'yjs') conforms to the repository coding
guideline.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 4acfca92-0258-42b2-8954-4f1f83861381
📒 Files selected for processing (12)
apps/electron/src/renderer/components/CanvasView.tsxapps/electron/src/renderer/components/DatabaseView.test.tsxapps/electron/src/renderer/components/DatabaseView.tsxapps/electron/src/renderer/lib/canvas-shell.test.tsapps/electron/src/renderer/lib/canvas-shell.tsapps/electron/vitest.config.tsdocs/explorations/0104_[-]_EXPLORE_DRAMATICALLY_SIMPLIFYING_THE_UX_AROUND_A_CANVAS_FIRST_PRIMARY_APP_INSPIRED_BY_AFFINE_MINIMIZING_BUTTONS_AND_CHROME_WITH_ZOOM_IN_DOCUMENTS_AND_DATABASES.mdpackages/canvas/src/__tests__/canvas-navigation-shell.test.tsxpackages/canvas/src/components/NavigationTools.tsxpackages/canvas/src/renderer/Canvas.tsxpackages/canvas/vitest.config.tsvitest.config.ts
| const linkedNode = createNode('embed', getLinkedDocumentPlacement(viewport, document.type), { | ||
| title: document.title, | ||
| linkedType: document.type | ||
| }) |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
rg -n -C2 \
"export type LinkedDocType|export type LinkedDocumentItem|export function getLinkedDocumentPlacement|addLinkedDocumentNode|getLinkedDocumentPlacement\\(viewport, document\\.type\\)" \
apps/electron/src/renderer/lib/canvas-shell.ts \
apps/electron/src/renderer/components/CanvasView.tsxRepository: crs48/xNet
Length of output: 3212
🏁 Script executed:
rg -n "export type LinkedDocumentItem" -A 10 apps/electron/src/renderer/lib/canvas-shell.tsRepository: crs48/xNet
Length of output: 250
Add a guard to exclude 'canvas' documents from this placement call.
getLinkedDocumentPlacement() explicitly expects Exclude<LinkedDocType, 'canvas'>, but document.type has type LinkedDocType which includes 'canvas'. Guard the call to ensure only 'page' or 'database' documents reach this code, or narrow the parameter type of addLinkedDocumentNode to exclude canvas documents.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/electron/src/renderer/components/CanvasView.tsx` around lines 171 - 174,
The call to getLinkedDocumentPlacement is passing document.type which may be
'canvas' but that function expects Exclude<LinkedDocType, 'canvas'>; add a guard
before creating linkedNode in addLinkedDocumentNode (or the surrounding
function) to early-return or handle document.type === 'canvas' so only 'page' or
'database' reach createNode('embed', getLinkedDocumentPlacement(...)), or
alternatively narrow the parameter type of addLinkedDocumentNode to exclude
'canvas'; update references to linkedNode, createNode, and
getLinkedDocumentPlacement accordingly so the placement call never receives a
'canvas' value.
| '@testing-library/react': resolve( | ||
| __dirname, | ||
| '../../packages/editor/node_modules/@testing-library/react' | ||
| ), |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python - <<'PY'
import json, pathlib
def dep_version(manifest, name):
return (
manifest.get('dependencies', {}).get(name)
or manifest.get('devDependencies', {}).get(name)
or manifest.get('peerDependencies', {}).get(name)
)
for rel in ('apps/electron/package.json', 'packages/editor/package.json'):
path = pathlib.Path(rel)
if not path.exists():
print(f'{rel}: missing')
continue
manifest = json.loads(path.read_text())
print(f'{rel}: `@testing-library/react` -> {dep_version(manifest, "@testing-library/react")}')
PYRepository: crs48/xNet
Length of output: 176
Remove the @testing-library/react alias that depends on packages/editor's installation.
Electron tests do not declare @testing-library/react in their own package.json, but the Vitest config resolves it from packages/editor/node_modules/@testing-library/react. This creates an implicit cross-package dependency that will break if packages/editor ever removes or updates this library, or in pruned installs.
Add @testing-library/react to apps/electron/package.json and allow Vitest to resolve it normally.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@apps/electron/vitest.config.ts` around lines 19 - 22, Remove the manual alias
entry for '@testing-library/react' in the vitest config (the resolve(...) block
that points to '../../packages/editor/node_modules/@testing-library/react') and
instead add '@testing-library/react' as a dependency/devDependency in the
apps/electron package.json so Vitest can resolve it normally; update the vitest
config to stop forcing that module path and rely on normal module resolution.
| {showNavigationTools && ( | ||
| <NavigationTools | ||
| viewport={viewport} | ||
| canvasBounds={canvasBounds} | ||
| onViewportChange={handleNavigationViewportChange} | ||
| position={navigationToolsPosition} | ||
| showZoomLabel={navigationToolsShowZoomLabel} | ||
| className={navigationToolsClassName} | ||
| style={navigationToolsStyle} | ||
| /> |
There was a problem hiding this comment.
Thread config.minZoom / config.maxZoom into this toolbar.
packages/canvas/src/components/NavigationTools.tsx still clamps its buttons and slider to 0.1–4. Wiring it in here without the canvas's configured bounds makes the shared controls disagree with wheel/pinch and shortcut behavior for any consumer using non-default zoom limits.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@packages/canvas/src/renderer/Canvas.tsx` around lines 688 - 697, Canvas's
NavigationTools is clamping to hardcoded 0.1–4, causing mismatch with the canvas
config; thread the canvas zoom limits through the toolbar by passing
config.minZoom and config.maxZoom into the NavigationTools instance in
Canvas.tsx (add props like minZoom={config.minZoom} and maxZoom={config.maxZoom}
to the component render), and update NavigationTools' props/types to accept and
use those minZoom/maxZoom values instead of the hardcoded 0.1/4 so the toolbar
slider/buttons respect the configured bounds.
| const workspaceAliases = { | ||
| '@xnetjs/canvas': new URL('./packages/canvas/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/cli': new URL('./packages/cli/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/core': new URL('./packages/core/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/crypto': new URL('./packages/crypto/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/data': new URL('./packages/data/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/data-bridge': new URL('./packages/data-bridge/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/devtools': new URL('./packages/devtools/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/editor': new URL('./packages/editor/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/formula': new URL('./packages/formula/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/history': new URL('./packages/history/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/hub': new URL('./packages/hub/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/identity': new URL('./packages/identity/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/network': new URL('./packages/network/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/plugins': new URL('./packages/plugins/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/query': new URL('./packages/query/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/react': new URL('./packages/react/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/sdk': new URL('./packages/sdk/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/sqlite/memory': new URL('./packages/sqlite/src/adapters/memory.ts', import.meta.url) | ||
| .pathname, | ||
| '@xnetjs/sqlite': new URL('./packages/sqlite/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/storage': new URL('./packages/storage/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/sync': new URL('./packages/sync/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/telemetry': new URL('./packages/telemetry/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/ui': new URL('./packages/ui/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/vectors': new URL('./packages/vectors/src/index.ts', import.meta.url).pathname, | ||
| '@xnetjs/views': new URL('./packages/views/src/index.ts', import.meta.url).pathname | ||
| } |
There was a problem hiding this comment.
🧩 Analysis chain
🌐 Web query:
In Node.js ESM, what problems does new URL('./file', import.meta.url).pathnamehave for filesystem paths compared withfileURLToPath(new URL('./file', import.meta.url)), especially on Windows or when the path contains spaces?
💡 Result:
Using new URL('./file', import.meta.url).pathname gives you the URL path component, not a real platform filesystem path, so it breaks in a few common cases that fileURLToPath(new URL('./file', import.meta.url)) handles correctly:
- Percent-encoding is left in place: spaces and non-ASCII characters stay encoded (e.g.
"hello world"→"/hello%20world","你好.txt"→"/%E4%BD%A0%E5%A5%BD.txt"), which is not a valid literal pathname for many filesystem APIs unless you manually decode it.fileURLToPath()decodes correctly. [1] - Windows drive letters get an extra leading
/and wrong separators:file:///C:/path/becomes"/C:/path/"via.pathname, notC:\path\.fileURLToPath()returns the proper Windows path. [1][2] - UNC paths lose the host:
file://nas/foo.txtbecomes"/foo.txt"via.pathname(host dropped), whilefileURLToPath()returns\\nas\foo.txt. [1]
In short: .pathname is for URL semantics; fileURLToPath() is the Node-supported way to turn a file: URL into a correct, decoded, platform-specific filesystem path. [1]
🏁 Script executed:
# Check if vitest.config.ts exists and examine the full file
if [ -f "vitest.config.ts" ]; then
echo "=== File exists ==="
wc -l vitest.config.ts
echo ""
echo "=== Full content ==="
cat -n vitest.config.ts
else
echo "vitest.config.ts not found"
fiRepository: crs48/xNet
Length of output: 6972
Use fileURLToPath for all workspace and mock aliases.
URL.pathname does not decode percent-encoded characters (spaces become %20, non-ASCII stays encoded) and mishandles Windows drive letters and UNC paths. This breaks alias resolution on Windows and in paths with spaces. Switch all 26 workspaceAliases entries and the mermaid alias (line 92) to use fileURLToPath(new URL(...)).
🛠️ Fix pattern
-import { defineConfig } from 'vitest/config'
+import { fileURLToPath } from 'node:url'
+import { defineConfig } from 'vitest/config'
const workspaceAliases = {
- '@xnetjs/canvas': new URL('./packages/canvas/src/index.ts', import.meta.url).pathname,
+ '@xnetjs/canvas': fileURLToPath(new URL('./packages/canvas/src/index.ts', import.meta.url)),
// ...apply to all remaining aliases
}
// Also fix line 92:
- mermaid: new URL('./packages/canvas/src/__mocks__/mermaid.ts', import.meta.url).pathname
+ mermaid: fileURLToPath(new URL('./packages/canvas/src/__mocks__/mermaid.ts', import.meta.url))🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@vitest.config.ts` around lines 7 - 34, The workspaceAliases entries are using
URL.pathname which can break on Windows and with percent-encoded paths; update
every alias value in workspaceAliases (all entries including
'@xnetjs/sqlite/memory') to wrap the URL with fileURLToPath(new URL(...))
instead of using .pathname, and likewise change the mermaid alias to use
fileURLToPath(new URL(...)); also add the import for fileURLToPath from 'url' at
the top of the file if it’s missing so all aliases resolve correctly across
platforms.
* feat(electron): finish canvas-first shell chrome - compress the focused database header into direct actions plus an overflow menu - replace custom canvas fit/reset controls with shared NavigationTools integration - add automated coverage for database focused chrome, shared canvas navigation, and viewport-centered placement - update the exploration checklist to reflect implemented and validated items * fix(test): resolve sqlite memory subpath in root vitest - alias @xnetjs/sqlite/memory to the workspace source adapter - allow root vitest runs and pre-push hooks to resolve sqlite memory tests without a package build --------- Co-authored-by: crs <crs@users.noreply.github.com>
* feat(electron): finish canvas-first shell chrome - compress the focused database header into direct actions plus an overflow menu - replace custom canvas fit/reset controls with shared NavigationTools integration - add automated coverage for database focused chrome, shared canvas navigation, and viewport-centered placement - update the exploration checklist to reflect implemented and validated items * fix(test): resolve sqlite memory subpath in root vitest - alias @xnetjs/sqlite/memory to the workspace source adapter - allow root vitest runs and pre-push hooks to resolve sqlite memory tests without a package build --------- Co-authored-by: crs <crs@users.noreply.github.com>
Summary
NavigationToolsintegrationTesting
pnpm --dir apps/electron exec vitest run src/renderer/components/DatabaseView.test.tsx src/renderer/lib/canvas-shell.test.tspnpm --dir packages/canvas exec vitest run src/__tests__/canvas-navigation-shell.test.tsx src/__tests__/navigation-tools.test.tspnpm exec vitest run packages/data/src/store/sqlite-adapter.test.ts packages/storage/src/adapters/sqlite.test.tspnpm typecheck && pnpm test)Summary by CodeRabbit
New Features
Tests
Documentation