Add CI workflow, render snapshots, and keyboard apply shortcuts
Some checks are pending
CI / test (push) Waiting to run

This commit is contained in:
Rbanh 2026-02-18 21:01:22 -05:00
parent bfb8275b2f
commit 9ce07c860b
5 changed files with 94 additions and 10 deletions

34
.gitea/workflows/ci.yml Normal file
View File

@ -0,0 +1,34 @@
name: CI
on:
push:
branches:
- main
pull_request:
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- name: Install deps
run: npm ci --ignore-scripts
- name: Static syntax checks
run: |
node --check src/server.js
node --check src/mcp-server.js
node --check src/layout.js
node --check src/compile.js
node --check frontend/app.js
- name: Run tests
run: npm test

View File

@ -38,6 +38,9 @@ Docs:
- `docs/release-checklist.md`
- `docs/operations-runbook.md`
CI:
- `.gitea/workflows/ci.yml` runs syntax checks + full test suite on push/PR.
## REST API
### `POST /compile`
@ -157,3 +160,9 @@ Tools:
- Selected panel editors for component properties, full pin properties, full symbol body/pin editing, and net connect/disconnect operations
- Click diagnostics to jump/flash focused net/component/pin
- Auto Layout and Auto Tidy actions
- Keyboard shortcuts:
- `Ctrl/Cmd+Z` undo
- `Ctrl/Cmd+Shift+Z` or `Ctrl/Cmd+Y` redo
- `Space` rotate selected components (or pan when no selection)
- `Alt+Enter` apply current selection editor (component/pin/net)
- `Alt+C` connect selected pin to chosen net

View File

@ -2990,6 +2990,28 @@ function setupEvents() {
el.canvasViewport.classList.add("dragging");
evt.preventDefault();
}
if (evt.altKey && evt.key === "Enter") {
evt.preventDefault();
if (state.selectedPin) {
el.applyPinPropsBtn.click();
return;
}
if (state.selectedNet) {
el.updateNetBtn.click();
return;
}
if (state.selectedRefs.length === 1 && state.selectedRef) {
el.updatePlacementBtn.click();
return;
}
}
if (evt.altKey && evt.key.toLowerCase() === "c" && state.selectedPin) {
evt.preventDefault();
el.connectPinBtn.click();
return;
}
});
window.addEventListener("keyup", (evt) => {

View File

@ -13,12 +13,12 @@
<p>AI-Native Schematic Workspace</p>
</div>
<div class="actions">
<button id="newProjectBtn">New</button>
<button id="loadSampleBtn">Load Sample</button>
<button id="importBtn">Import JSON</button>
<button id="exportBtn">Export JSON</button>
<button id="autoLayoutBtn">Auto Layout</button>
<button id="autoTidyBtn">Auto Tidy</button>
<button id="newProjectBtn" aria-label="Create new project">New</button>
<button id="loadSampleBtn" aria-label="Load sample project">Load Sample</button>
<button id="importBtn" aria-label="Import Schemeta JSON file">Import JSON</button>
<button id="exportBtn" aria-label="Export Schemeta JSON file">Export JSON</button>
<button id="autoLayoutBtn" aria-label="Run automatic layout">Auto Layout</button>
<button id="autoTidyBtn" aria-label="Run automatic tidy layout">Auto Tidy</button>
<button id="undoBtn" title="Undo (Ctrl/Cmd+Z)">Undo</button>
<button id="redoBtn" title="Redo (Ctrl/Cmd+Shift+Z)">Redo</button>
<label class="inlineSelect">
@ -54,10 +54,10 @@
<section class="pane center">
<div class="canvasTools">
<button id="zoomOutBtn">-</button>
<button id="zoomResetBtn">100%</button>
<button id="zoomInBtn">+</button>
<button id="fitViewBtn">Fit</button>
<button id="zoomOutBtn" aria-label="Zoom out">-</button>
<button id="zoomResetBtn" aria-label="Reset zoom">100%</button>
<button id="zoomInBtn" aria-label="Zoom in">+</button>
<button id="fitViewBtn" aria-label="Fit schematic to viewport">Fit</button>
<label class="inlineCheck"><input id="showLabelsInput" type="checkbox" checked /> Labels</label>
<span id="compileStatus">Idle</span>
</div>

View File

@ -0,0 +1,19 @@
import test from "node:test";
import assert from "node:assert/strict";
import { createHash } from "node:crypto";
import { compile } from "../src/compile.js";
import fixture from "../examples/esp32-audio.json" with { type: "json" };
function svgHash(svg) {
return createHash("sha256").update(String(svg ?? "")).digest("hex");
}
test("render output for reference fixture remains deterministic", () => {
const outA = compile(fixture, { render_mode: "schematic_stub", show_labels: true });
const outB = compile(fixture, { render_mode: "schematic_stub", show_labels: true });
assert.equal(outA.ok, true);
assert.equal(outB.ok, true);
assert.equal(outA.svg, outB.svg);
assert.equal(svgHash(outA.svg), "c7a3cd161b6129b53e335d689e13b5425ccca6692f263245e3bf2d7b37aab06a");
});