Skip to content

feat: command palette, UI polish, and file reorganization - #10

Merged
Ocean82 merged 1 commit into
mainfrom
pr/ui-improvements
Jul 17, 2026
Merged

feat: command palette, UI polish, and file reorganization#10
Ocean82 merged 1 commit into
mainfrom
pr/ui-improvements

Conversation

@Ocean82

@Ocean82 Ocean82 commented Jul 17, 2026

Copy link
Copy Markdown
Owner

UI and organizational improvements.

Changes:

  • New CommandPalette component with keyboard shortcut support
  • Improved SpreadsheetGrid, ChatPanel, MenuBar, ConditionalFormatDialog
  • workbookJson import/export with tests
  • Renamed src/ai/skills/ to src/ai/analysis/ (clearer naming)
  • Renamed src/data/skills.ts to src/data/chatPresets.ts
  • Updated AI modules (brain, queryEngine, sheetProfile, responseBuilder)
  • Added recommended VS Code extensions

Summary by Sourcery

Introduce a keyboard-driven command palette, JSON workbook backup/restore, and AI action previews, while refining conditional formatting, analysis modules, and UI copy.

New Features:

  • Add a global CommandPalette with Ctrl/Cmd+K shortcut for quick access to chat, templates, tools, export, and undo/redo.
  • Support exporting and importing workbooks as structured JSON packages with normalization and tests.
  • Display staged AI cell changes in the grid with visual highlights, tooltips, and a bottom bar to apply or reject actions.
  • Enable conditional formatting data bars with proportional fills across column peer values.

Enhancements:

  • Adjust SpreadsheetGrid visuals and conditional formatting to support data bars and AI preview styling.
  • Improve AI analysis inputs by normalizing raw cell values via scalar formatting and updating sheet/profile/query tests.
  • Clarify Skills system documentation and SkillsPanel labeling to reflect preset-based workflows.
  • Route chat focusing through a custom event so the command palette can own the Ctrl/Cmd+K shortcut.
  • Update build tooling to run TypeScript typechecking before Vite builds.
  • Refine MenuBar file actions to include JSON backup/restore with assistant messaging.
  • Tweak ChatPanel placeholder to reference command usage and minor UI polish across dialogs.

Build:

  • Add a dedicated typecheck script and gate the build on successful TypeScript typechecking.

Documentation:

  • Update Skills README to explain the current presets/analysis architecture and correct data source references.

Tests:

  • Add tests for conditional formatting data bar behavior and width calculations.
  • Add tests for workbook JSON serialization, parsing, and normalization.
  • Update AI-related tests (brain, sheetProfile, queryEngine) for new insights and sheet shape expectations.

Chores:

  • Reorganize AI modules from a skills directory to an analysis directory and rename skills data to chat presets.
  • Add recommended VS Code extensions configuration for the project.

- Add CommandPalette component with keyboard shortcut support
- Improve SpreadsheetGrid, ChatPanel, MenuBar, ConditionalFormatDialog
- Add workbookJson import/export with tests
- Rename src/ai/skills/ to src/ai/analysis/ (clearer naming)
- Rename src/data/skills.ts to src/data/chatPresets.ts
- Update AI modules (brain, queryEngine, sheetProfile, responseBuilder)
- Add recommended VS Code extensions
@sourcery-ai

sourcery-ai Bot commented Jul 17, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds a keyboard-driven command palette, workbook JSON backup/restore utilities with tests, AI action preview UX in the grid, conditional formatting data bar support, and aligns AI analysis modules and tests while tightening type safety and editor setup.

Sequence diagram for keyboard-driven command palette and chat focus

sequenceDiagram
  actor User
  participant App
  participant CommandPalette
  participant Document
  participant ChatPanel

  User->>Document: keydown (Ctrl/Cmd+K)
  Document->>App: keydown handler
  App-->>App: setShowCommandPalette(true)
  App->>CommandPalette: render open=true
  User->>CommandPalette: select Focus chat input
  CommandPalette-->>App: onFocusChat()
  App-->>App: setShowChat(true), setIsMobileChatOpen(true)
  App->>Document: dispatch smartsht:focus-chat
  Document->>ChatPanel: smartsht:focus-chat event
  ChatPanel-->>ChatPanel: inputRef.focus()
Loading

Sequence diagram for AI action previews and apply/reject in SpreadsheetGrid

sequenceDiagram
  participant Agent
  participant responseBuilder
  participant Store
  participant SpreadsheetGrid
  actor User

  Agent->>responseBuilder: toolResultToChatMessage(result, previewContext)
  responseBuilder-->>Store: addMessage(ChatMessage with actions and preview)
  SpreadsheetGrid->>Store: useStore()
  SpreadsheetGrid-->>SpreadsheetGrid: findActivePendingPreview(messages)
  SpreadsheetGrid-->>User: render AI staged banner and cell highlights
  User->>SpreadsheetGrid: click Apply
  SpreadsheetGrid->>Store: applyAction(pendingPreview.action.id)
  Store-->>SpreadsheetGrid: updated workbook, messages
  User->>SpreadsheetGrid: click Reject
  SpreadsheetGrid->>Store: rejectAction(pendingPreview.action.id)
  Store-->>SpreadsheetGrid: cleared pendingPreview
Loading

Flow diagram for workbook JSON backup and restore utilities

flowchart TD
  A[WorkbookData] --> B[serializeWorkbookPackage]
  B --> C[exportWorkbookToJson]
  C --> D[Download .smartsht.json]

  E[JSON file] --> F[importWorkbookFromJsonFile]
  F --> G[parseWorkbookJson]
  G --> H[normalizeImportedWorkbook]
  H --> I[WorkbookData loaded via loadWorkbookData]
Loading

File-Level Changes

Change Details Files
Introduce a keyboard-driven command palette for common actions and template workflows, integrated with chat focus and file/JSON operations.
  • Add CommandPalette component with searchable commands, keyboard navigation, and categories.
  • Wire Ctrl/Cmd+K in App to open the palette and delegate chat focusing via a custom event.
  • Connect palette actions to templates, chart/pivot/conditional format dialogs, undo/redo, and export flows including optional JSON backup/restore hooks.
src/components/CommandPalette.tsx
src/App.tsx
src/components/ChatPanel.tsx
Implement workbook JSON backup/restore IO utilities and integrate them into the menu and command palette, with validation and normalization.
  • Add workbookJson module to serialize, download, parse, and normalize workbook packages from JSON files.
  • Hook JSON backup/restore into MenuBar and App via hidden file inputs and callbacks, including assistant messaging and history pushes.
  • Cover JSON IO with tests for round-trip, bare WorkbookData, normalization, and invalid payload handling.
src/io/workbookJson.ts
src/io/workbookJson.test.ts
src/components/MenuBar.tsx
src/App.tsx
Enhance SpreadsheetGrid with AI pending action previews and conditional formatting data bars, including scroll-to-preview behavior.
  • Derive pendingPreview from chat messages and scroll the first affected cell into view when a new preview appears.
  • Visually mark cells with staged AI changes, including badge, tooltip with old/new values, and apply/reject footer bar wired to store actions.
  • Add data bar conditional formatting: compute peer column values, derive proportional widths, and render bar overlays while excluding them from bgColor merging.
src/components/SpreadsheetGrid.tsx
src/lib/conditionalFormat.ts
src/lib/conditionalFormat.test.ts
src/lib/pendingActionPreview.ts
Refine AI analysis stack to use normalized scalar cell values and reorganize skill modules into an analysis namespace, updating tests accordingly.
  • Replace usage of raw cell values with cellScalar in buildContext, sheetInsights, sheetProfile, and XLSX export to standardize scalar representations.
  • Move budget, reporting, and cleaning modules from ai/skills to ai/analysis and update brain imports and related references.
  • Adjust AI tests (queryEngine, sheetProfile, brain) to reflect SheetData shape changes and richer insights structure.
src/ai/buildContext.ts
src/ai/sheetInsights.ts
src/ai/sheetProfile.ts
src/io/xlsx.ts
src/ai/brain.ts
src/ai/queryEngine.test.ts
src/ai/sheetProfile.test.ts
src/ai/brain.test.ts
Improve ConditionalFormatDialog UX and skills-related UI copy to reflect data bars and the current presets/analysis architecture.
  • Add a Data bars condition option and update label copy to distinguish bar color from highlight color.
  • Update SkillsPanel to label presets with "preset" vs number of actions instead of raw tool count.
  • Clarify skills README to describe chat presets, analysis modules location, and tool registry mapping.
src/components/ConditionalFormatDialog.tsx
src/components/SkillsPanel.tsx
src/skills/README.md
Support richer AI tool action previews for mutate-type tools and tighten TypeScript/typechecking workflow.
  • Extend toolResultToChatMessage to build preview changes via buildActionPreview when previewContext is provided and params lack explicit previewChanges.
  • Use the generic CellChange type for preview data and include approximate change counts in action descriptions.
  • Add a typecheck npm script and make build run tsc --noEmit before Vite build.
src/ai/responseBuilder.ts
package.json
src/lib/previewBuilders.ts
Add editor configuration and minor structural/test tweaks for consistency and ergonomics.
  • Introduce recommended VS Code extensions configuration file.
  • Ensure SheetData test fixtures include columnWidths/rowHeights and use undefined sortConfig instead of null for consistency.
  • Miscellaneous small messaging/placeholder copy tweaks in ChatPanel and other components.
.vscode/extensions.json
src/ai/queryEngine.test.ts
src/ai/sheetProfile.test.ts
src/components/ChatPanel.tsx

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@Ocean82, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 54 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bad80316-7c88-4079-be03-09c53e88dd57

📥 Commits

Reviewing files that changed from the base of the PR and between 395ca32 and 0c6797b.

📒 Files selected for processing (28)
  • .vscode/extensions.json
  • package.json
  • src/App.tsx
  • src/ai/analysis/budget.test.ts
  • src/ai/analysis/budget.ts
  • src/ai/analysis/cleaning.ts
  • src/ai/analysis/reporting.ts
  • src/ai/brain.test.ts
  • src/ai/brain.ts
  • src/ai/buildContext.ts
  • src/ai/queryEngine.test.ts
  • src/ai/responseBuilder.ts
  • src/ai/sheetInsights.ts
  • src/ai/sheetProfile.test.ts
  • src/ai/sheetProfile.ts
  • src/components/ChatPanel.tsx
  • src/components/CommandPalette.tsx
  • src/components/ConditionalFormatDialog.tsx
  • src/components/MenuBar.tsx
  • src/components/SkillsPanel.tsx
  • src/components/SpreadsheetGrid.tsx
  • src/data/chatPresets.ts
  • src/io/workbookJson.test.ts
  • src/io/workbookJson.ts
  • src/io/xlsx.ts
  • src/lib/conditionalFormat.test.ts
  • src/lib/conditionalFormat.ts
  • src/skills/README.md

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Hey - I've reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@Ocean82
Ocean82 merged commit 31264e9 into main Jul 17, 2026
2 of 3 checks passed
@Ocean82
Ocean82 deleted the pr/ui-improvements branch July 19, 2026 11:40
Ocean82 added a commit that referenced this pull request Sep 4, 2026
…env)

Record the 10 review items that couldn't be verified in a sandbox (live LLM keys, DB/S3/AWS, ONNX models, browser matrix, load). Notes where this session already added coverage (real-engine test tier for #1, SSRF hardening + tests for #9) and resolves two from code: #6 PM2 cwd is set in the committed server/ecosystem.config.cjs (models resolve correctly when started via it), and #10 vite.config sets no allowedHosts (strict default; dev server not deployed).
Ocean82 added a commit that referenced this pull request Sep 4, 2026
… guards, real-engine tests, docs (#22)

* deploy: frontend rollback, stale-vector regen via phrase hash, single-source phrases

- deploy.sh: extract mirror_frontend(); rebuild+remirror frontend from
  PREV_COMMIT on health-check rollback so the live SPA matches the API.
- intent-vectors.bin format v2: embed FNV-1a hash of the phrase set. Client
  rejects a binary whose hash no longer matches (falls back to runtime
  bootstrap); precompute self-skips when current, regenerates when stale.
- deploy.sh always runs model:precompute when the model is present (was gated
  on file absence, which shipped stale vectors after a phrase edit).
- Eliminate INTENT_PHRASES duplication: single source in shared/intentPhrases.js
  imported by both intentEmbeddings.ts and precompute-embeddings.mjs.
- Update intentVectorsBin.test.ts to v2 format; add stale-hash and parity tests.

* intent parser return with question

* fix(parser): claim bare 'add a row' for clarification; align README with real instant-op coverage

The addRow branch required trailing values, so the README's own 'add a row' example fell through to the LLM. Make the values capture optional and return a clarifying question when a row has no values (add_row rejects empty rows, so we ask instead of emitting a failing call). Valued rows still parse straight to add_row.

Rewrite the Intent Parser section to name operations that are genuinely instant (sort, formatting, set cell, add a row of values, delete a row, find & replace, percentage tweaks) and note totals/group-bys are matched locally by the goal router. Drops the implication that bare add-a-row, hide/freeze/merge are instant.

Add a parser.gaps regression covering the bare 'add a row' clarification.

* docs: clarify local/open-mode run and that Clerk/Stripe keys are for hosted deploys only

The app runs fully without auth when VITE_CLERK_PUBLISHABLE_KEY is blank, but a fresh clone had no explanation of this and the .env.example _live_ placeholders read as required. Add a 'Running locally' README section and inline .env.example notes explaining open mode, and that Clerk/Stripe/cloud-sync are only needed for a self-hosted gated instance using the operator's own keys.

* fix(server): harden BYOK against SSRF (redirects, DNS rebinding, IP-encoding bypasses)

The BYOK baseUrl validator only string-matched hostnames, and the outbound fetches followed redirects by default. A user could reach internal services / the cloud metadata endpoint via: a public URL that 302s to an internal address; a public DNS name resolving to a private IP (rebinding); or alternate IP encodings (decimal/octal/hex/IPv6-mapped) that dodged the string checks.

Fixes: (1) isPublicHttpsByokUrl now canonicalizes IP literals and checks full private/loopback/link-local/CGNAT/ULA/IPv4-mapped ranges; (2) new async assertPublicByokHost resolves the host and rejects private resolved IPs, wired into both BYOK call sites before fetch; (3) both openaiCompatible fetches use redirect:'manual' and refuse 3xx/opaqueredirect. Adds regression tests. Full server suite 317/317.

* chore(deps): remove xlsx CDN SPOF, patch server audit findings, gate CI audit at critical + weekly advisory sweep

Vendor the official SheetJS xlsx-0.20.3 tarball (SHA512 matches the lockfile integrity byte-for-byte) and pin xlsx to file:vendor/, so installs no longer depend on cdn.sheetjs.com uptime (which was hard-failing CI and deploy.sh on outages/proxies).

Apply available server audit fixes: nanoid 3.3.16->3.3.18 (GHSA-2v37-7h3g-55p8, high) and qs 6.15.3->6.16.0 (two moderate). Lockfile-only transitive bumps; npm audit --prefix server now clean; server suite 317/317.

CI: replace 'npm audit --audit-level=high || true' with 'npm audit --audit-level=critical' (no || true) so critical fixable advisories fail the build, and add a scheduled/dispatch advisory-only 'audit' job that opens/updates a dependencies-labeled issue on high-or-worse findings instead of blocking PRs.

* docs(deploy): note vendored xlsx tarball must survive checkout

xlsx is now pinned to file:vendor/xlsx-0.20.3.tgz, so npm ci resolves it from the committed tarball. Add a Pending item in PRODUCTION-TODO.md and an inline comment at deploy.sh's npm ci step so a future deploy doesn't drop vendor/ and break the install.

* fix(persistence): surface localStorage quota/failure and quarantine corrupt state instead of silent data loss

savePersistedState swallowed all errors, so a full localStorage silently no-oped every 400ms autosave while the user believed work was saved. loadPersistedState returned null on any parse error, discarding all workbooks + chat with no recovery. Now: savePersistedState returns a LocalSaveResult (ok | quota | error) and main.tsx surfaces a single non-blocking toast per quota episode; loadPersistedState quarantines the raw payload to smartsht-state-v1.corrupt before returning null. persistence.ts stays UI-free. Adds 4 tests (8/8 pass); typecheck clean.

* docs: record deferred persistence follow-ups (LRU eviction, IndexedDB migration)

Capture the two persistence improvements deliberately left out of 04b3a62, with scope, gotchas, and the stability tradeoff for the IndexedDB move, so they can be picked up later without re-deriving the context.

* fix(health): add strict readiness (503 on DB/S3/Clerk down) and gate deploy.sh on it

/health always returned 200 and its ok flag reflected only AI-provider liveness, so deploy.sh's curl -sf gate reported a DB-broken deploy healthy and never rolled back. Add ?strict=1 which returns 503 unless db.ok && s3.ok && clerk.ok (mirrors config.ts criticality: cloud save/sharing/versions/usage need DB+S3, auth needs Clerk). AI providers and Stripe stay informational — they degrade gracefully, so gating rollback on them would revert a healthy deploy. Plain /health is unchanged for liveness probes. deploy.sh now curls /health?strict=1. Adds 6 tests; server suite 323/323.

* docs(deploy): note strict health gate requires DB/S3/Clerk on next deploy

deploy.sh now gates rollback on /health?strict=1 (503 unless DB+S3+Clerk healthy). Record in PRODUCTION-TODO so a 503-driven rollback is read as a real subsystem outage, not a false alarm, and note AI providers/Stripe are excluded from the gate.

* test(engine): add real-WASM integration tier and clearly label the stubbed unit tier

Every vitest run aliased the WASM formula engine to a toy stub (arithmetic + SUM + single refs), so the real engine — dependency graph, recalc, cross-sheet refs, circular detection, error propagation — had zero automated coverage even though the auditor, grid, and chat actions depend on it.

Rename the stub to formualizer.stub.ts with a header stating it is not the real engine. Add vitest.integration.config.ts (vite-plugin-wasm, no alias, only *.realengine.test.ts) and src/engine/formualizer.realengine.test.ts (8 tests: recalc after edit, multi-hop propagation, cross-sheet refs, #CIRC!, #DIV/0!, #NAME? — all verified against the real engine). Add npm script test:realengine and wire it into CI. Exclude *.realengine.test.ts from the stubbed unit tier so it isn't run against the stub. Unit tier 1463/1463, real-engine tier 8/8.

WASM-in-Node proved viable, so no Playwright fallback needed. Structural insert/delete ref-rewrite was dropped: not an API this engine exposes.

* docs(deploy): correct build-artifact shape; assert wasm in deploy; gzip wasm

DEPLOY.md claimed the frontend is a single dist/index.html and showed a cp dist/index.html snippet that would 404 the WASM engines. In reality vite-plugin-singlefile inlines JS/CSS but the build emits external .wasm engines (formualizer ~8.6MB, ONNX ~27MB) + worker bundles under dist/assets/. Correct the docs (artifact list, ls verify, rsync the whole tree, /var/www layout).

deploy.sh: assert dist/assets contains .wasm after the build (fail → rollback) so a broken build can't ship an engine-less SPA. nginx: add application/wasm to gzip_types so the large binaries are compressed in transit (~4x); brotli left as a documented opt-in since ngx_brotli may be absent and would fail nginx -t.

Verified already-handled (no change): wasm 30d cache + hashed names, lazy ONNX worker spawn, SW version-keyed cache eviction.

* chore: repo hygiene - drop tsc dumps & unused assets, untrack ignored dirs, fix Node version & stale roadmap

Remove committed debugging leftovers (tsc-output.txt, tsc-result.txt) and 32 unused src/assets image files (verified zero references repo-wide). Untrack .idea/.vscode/.junie/docs/superpowers via git rm --cached to honor .gitignore (files kept locally).

README: Node prerequisite 20+ -> 22+ to match package.json engines and CI. Refresh the stale roadmap: auto-insights on import, auditor auto-run, and the cell inspector are already shipped (verified) - move them to a shipped note and list the real next items (guided navigation) from roadmap-v1.md. typecheck clean after removals.

* docs: sync GROQ_MODEL to live prod (qwen3.6-27b), complete README env table, drop stale model:setup marker

Verified against the live server: /opt/smartsht/.env has GROQ_MODEL=qwen/qwen3.6-27b, but server/.env.production, both .env.example files, and the README said openai/gpt-oss-120b. Align all four to the live value (config.ts keeps gpt-oss-120b only as its unset-fallback default; qwen3.6-27b is already in KNOWN_GROQ_MODELS).

README config: mark server/.env.example + docs/ENV.md as the authoritative full env list, note the table is a starter subset, and add the missing CLERK_*/STRIPE_*/DATABASE_URL/S3_*/AWS_*/TRUST_PROXY/WORKBOOK_BODY_LIMIT/FREE_CLOUD_WORKBOOK_LIMIT/MAX_WORKBOOK_VERSIONS rows. Remove the stray '##deprecated' on npm run model:setup.

PRODUCTION-TODO: add a follow-up to verify at runtime which .env file and model ids/paths the smartsht-api process actually loads, since this drift was only caught by manual SSH.

* docs: capture verification backlog (items needing a live/integration env)

Record the 10 review items that couldn't be verified in a sandbox (live LLM keys, DB/S3/AWS, ONNX models, browser matrix, load). Notes where this session already added coverage (real-engine test tier for #1, SSRF hardening + tests for #9) and resolves two from code: #6 PM2 cwd is set in the committed server/ecosystem.config.cjs (models resolve correctly when started via it), and #10 vite.config sets no allowedHosts (strict default; dev server not deployed).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant