Add CI workflow, render snapshots, and keyboard apply shortcuts
Some checks are pending
CI / test (push) Waiting to run
Some checks are pending
CI / test (push) Waiting to run
This commit is contained in:
parent
bfb8275b2f
commit
9ce07c860b
34
.gitea/workflows/ci.yml
Normal file
34
.gitea/workflows/ci.yml
Normal 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
|
||||||
@ -38,6 +38,9 @@ Docs:
|
|||||||
- `docs/release-checklist.md`
|
- `docs/release-checklist.md`
|
||||||
- `docs/operations-runbook.md`
|
- `docs/operations-runbook.md`
|
||||||
|
|
||||||
|
CI:
|
||||||
|
- `.gitea/workflows/ci.yml` runs syntax checks + full test suite on push/PR.
|
||||||
|
|
||||||
## REST API
|
## REST API
|
||||||
|
|
||||||
### `POST /compile`
|
### `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
|
- 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
|
- Click diagnostics to jump/flash focused net/component/pin
|
||||||
- Auto Layout and Auto Tidy actions
|
- 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
|
||||||
|
|||||||
@ -2990,6 +2990,28 @@ function setupEvents() {
|
|||||||
el.canvasViewport.classList.add("dragging");
|
el.canvasViewport.classList.add("dragging");
|
||||||
evt.preventDefault();
|
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) => {
|
window.addEventListener("keyup", (evt) => {
|
||||||
|
|||||||
@ -13,12 +13,12 @@
|
|||||||
<p>AI-Native Schematic Workspace</p>
|
<p>AI-Native Schematic Workspace</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="actions">
|
<div class="actions">
|
||||||
<button id="newProjectBtn">New</button>
|
<button id="newProjectBtn" aria-label="Create new project">New</button>
|
||||||
<button id="loadSampleBtn">Load Sample</button>
|
<button id="loadSampleBtn" aria-label="Load sample project">Load Sample</button>
|
||||||
<button id="importBtn">Import JSON</button>
|
<button id="importBtn" aria-label="Import Schemeta JSON file">Import JSON</button>
|
||||||
<button id="exportBtn">Export JSON</button>
|
<button id="exportBtn" aria-label="Export Schemeta JSON file">Export JSON</button>
|
||||||
<button id="autoLayoutBtn">Auto Layout</button>
|
<button id="autoLayoutBtn" aria-label="Run automatic layout">Auto Layout</button>
|
||||||
<button id="autoTidyBtn">Auto Tidy</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="undoBtn" title="Undo (Ctrl/Cmd+Z)">Undo</button>
|
||||||
<button id="redoBtn" title="Redo (Ctrl/Cmd+Shift+Z)">Redo</button>
|
<button id="redoBtn" title="Redo (Ctrl/Cmd+Shift+Z)">Redo</button>
|
||||||
<label class="inlineSelect">
|
<label class="inlineSelect">
|
||||||
@ -54,10 +54,10 @@
|
|||||||
|
|
||||||
<section class="pane center">
|
<section class="pane center">
|
||||||
<div class="canvasTools">
|
<div class="canvasTools">
|
||||||
<button id="zoomOutBtn">-</button>
|
<button id="zoomOutBtn" aria-label="Zoom out">-</button>
|
||||||
<button id="zoomResetBtn">100%</button>
|
<button id="zoomResetBtn" aria-label="Reset zoom">100%</button>
|
||||||
<button id="zoomInBtn">+</button>
|
<button id="zoomInBtn" aria-label="Zoom in">+</button>
|
||||||
<button id="fitViewBtn">Fit</button>
|
<button id="fitViewBtn" aria-label="Fit schematic to viewport">Fit</button>
|
||||||
<label class="inlineCheck"><input id="showLabelsInput" type="checkbox" checked /> Labels</label>
|
<label class="inlineCheck"><input id="showLabelsInput" type="checkbox" checked /> Labels</label>
|
||||||
<span id="compileStatus">Idle</span>
|
<span id="compileStatus">Idle</span>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
19
tests/render-regression.test.js
Normal file
19
tests/render-regression.test.js
Normal 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");
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user