104 Commits

Author SHA1 Message Date
0ace92e15d Fix MCM and EPC missing tagpaths/color/state/priority
MCM: was returning null for tagpath — now gets System/{mcm}/MCM09
EPC: emitEpc() was building <g> without Ignition data attributes —
now includes igAttrs (data-tagpath, data-color, data-state, data-priority)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:30:35 +04:00
015e2406b0 Prefix group element names with s_str_ for Designer search
Group names now format as s_str_{id} (e.g. s_str_UL17_20_VFD)
for searchability in Ignition Designer.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:24:20 +04:00
12a2ad62bf Fix DPM/MCM bindings: elements[0].fill.paint (not elements[1])
Matches Example pattern — first triangle path gets the color binding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:21:36 +04:00
ba9b45a43e Add EPC-specific bindings and fix EPC tag path
EPC bindings: elements[0].stroke.paint (polyline) and
elements[1].elements[1].fill.paint (icon inner path) get color.
EPC tag path: Station/Emergency_Pull_Cord (not VFD/APF).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:20:45 +04:00
1cd4c9dc44 Always wrap SVG symbols in <g> so all get Ignition metadata
Single-element SVGs (like FIO paths) were exported as bare <path>
without tagpaths/color/state/priority. Now all symbols are wrapped
in a <g> group with the Ignition data attributes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:14:25 +04:00
d84ff495b5 Persist Ignition project and view path between sessions via localStorage
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:10:05 +04:00
034934be71 Restore bindings for FIOM, FIOH, SIO, EPC, MCM — they use same bindings
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:04:14 +04:00
611d8d2dd0 Skip Ignition bindings for FIOM, FIOH, SIO, EPC, and MCM
These are infrastructure/special devices that don't use standard
color/state/priority bindings. EPC has specialized stroke bindings,
MCM has unique structure, FIO/SIO are network nodes without
operational state displays.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:57:45 +04:00
c72d0cceee Fix DPM/button bindings and strip _PB from tag paths
DPM: only elements[1] gets fill.paint binding (black triangle),
elements[0] and [2] keep their static colors.

Buttons (JR, S, SS, EN): no elements[0].fill.paint binding —
background rect keeps static color. Only text gets contrast binding.

Tag paths: strip _PB/_SPB/_STPB suffixes from button labels to
match PLC naming (UL17_19_S1 not UL17_19_S1_PB).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:49:25 +04:00
1f46c89479 Remove all vertical (_v) symbol variants from codebase
Users can rotate any symbol manually — the pre-rotated _v variants
were redundant. Removed from SYMBOLS array, PRIORITY_TYPES,
SPACING_EXEMPT, RECT_CONVEYANCE, OVERLAY_IDS, OUTDATED_SIZES,
and all type-check functions.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:47:26 +04:00
0f50ab27ae Add full Ignition Perspective view.json generator with bindings, scripts, and controls
Extracts all CDW5_SCADA boilerplate (zoom controls, markdown tooltip,
pan/wheel events, element color/state/priority tag bindings, display
filters, Start/Stop special-case bindings) into a new ignition-view.ts
module.  deployToIgnition() now produces the complete view.json instead
of a minimal skeleton.  Also adds ignitionViewPath to the store/toolbar
and routes it through the deploy endpoint so views land under the correct
sub-folder (e.g. DetailedView/MCM09).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 01:02:39 +04:00
3f122d9177 Refactor: extract shared code, add constants, clean up dispatch
- Extract parseConveyanceLabel to shared label-utils.ts (was duplicated)
- Add EXTENDO_CONFIG, LABEL_CONFIG, CONVEYANCE_STYLE to symbol-config.ts
- Replace all hardcoded fill/stroke/lineWidth with CONVEYANCE_STYLE
- Replace magic font numbers (14, 4, 0.5) with LABEL_CONFIG constants
- Extract drawSpurSymbol, drawExtendoSymbol, drawRectConveyanceSymbol
  from inline code — drawSymbolBody is now a clean dispatch
- Convert getIgnitionTagPath from 18 if-statements to data-driven table
- Add THEME.marquee for selection rectangle colors
- Remove no-op assignment in parseConveyanceLabel

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 22:58:36 +04:00
8a52449dfe Render all non-conveyance devices on top in SVG/JSON export
All small/overlay devices (PE, FIO, BCN, SOL, JR, S, SS, EPC, DPM,
PDP, MCM, PS, diverter, camera) render LAST so they're on top of
conveyors and clickable in SCADA.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 16:28:09 +04:00
006623c43d Rewrite tag path mapping from actual Excel device suffixes
Derived all suffix->path mappings from the devices-manifest.json:
- VFD, EPC → VFD/APF
- TPE, BDS*_R/S, TS*_R/S → Sensor/Tracking
- LPE → Sensor/Long_Range
- JPE → Sensor/Jam
- FPE → Sensor/Full
- PS → Sensor/Pressure
- FIOM → Network_Node/FIO
- FIOH → Network_Node/HUB
- SIO → Network_Node/SIO
- DPM → Network_Node/DPM
- SS*_SPB/STPB → Station/Start_Stop
- CH*_EN*_PB → Station/Jam_Reset_Chute_Bank
- JR*_PB → Station/Jam_Reset
- S*_PB → Station/Start
- BCN → Beacon
- SOL, DIV*_SOL → Solenoid
- DIV*_LS → Diverter
- PDP → PDP

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:43:57 +04:00
eb0b346e1a Fix tag paths to match Ignition tag tree exactly
- BCN → Beacon (not Solenoids)
- SOL → Solenoid (not Solenoids)
- Added: Chute, Tipper, Diverter, Extendo, Chute Enable, Package Release

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:41:35 +04:00
cb94116a87 Fix resource.json timestamp: strip milliseconds for Ignition compat
Ignition's JSON parser can't handle ISO timestamps with milliseconds
(2026-03-30T19:31:53.623Z). Strip to seconds (2026-03-30T19:31:53Z).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:35:16 +04:00
46cec1c12e Add SHA-256 lastModificationSignature to resource.json
Ignition requires this signature to validate resource integrity.
Without it, the Designer fails with "Error reading updated project".

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:32:00 +04:00
99db2d5da8 Write .deploy-pending trigger file for gateway timer script
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:23:56 +04:00
48b6a5b50c Update deploy alert: tell user to reopen project in Designer
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:20:20 +04:00
4e48493cf0 Stop deleting view folder on deploy — just overwrite files
Deleting the folder caused Ignition's ResourceTreeFileWatcher to error
when cleaning up cached resource copies. Now just overwrites in place.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:16:41 +04:00
cef76524b3 Add project scan trigger after deploy via gateway message handler
Deploy now attempts to trigger a scanProject message handler after
writing files. Requires a Gateway Message Handler named "scanProject"
in Ignition Designer with: IgnitionGateway.get().getProjectManager().requestScan()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:15:24 +04:00
dc86f65fa7 Simplify deploy: just write files, no restart attempt
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:12:57 +04:00
8e2f837fb9 Delete and recreate view folder on deploy to force Ignition detection
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:10:42 +04:00
0d4075d126 Write scan trigger file on deploy for gateway timer script pickup
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:06:21 +04:00
937153d611 Touch project.json on deploy to help trigger Ignition rescan
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:03:15 +04:00
2130ad523a Fix view.json: remove version/custom from child component
Working Ignition views only have meta, position, props, type on child
components — no version or custom fields.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:52:44 +04:00
1ce7783a2e Fix Ignition view.json: match working Testing_View structure
- Component gets meta.name + position at same level as type/props
- Root container uses props.mode="percent" not direction="column"

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:49:04 +04:00
a0ceb56309 Add Ignition deploy: write view.json directly to Ignition project dir
- New "Ignition" section in toolbar with Project and View name fields
- View name defaults to current MCM
- "Deploy to Ignition" button writes view.json + resource.json to:
  C:/Program Files/Inductive Automation/Ignition/data/projects/{Project}/
  com.inductiveautomation.perspective/views/{ViewName}/
- Vite dev server plugin handles file writing via /api/deploy-ignition
- view.json wraps ia.shapes.svg component in proper Perspective view structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:44:11 +04:00
2c38950cb7 Add Ignition SCADA JSON export (ia.shapes.svg format)
New "SCADA" button generates Ignition-compatible JSON that can be
directly pasted into Ignition Perspective views. Converts SVG elements
to Ignition's ia.shapes.svg JSON format with:
- Proper element types (group, rect, path, text, polyline, circle)
- Fill/stroke as {paint, width} objects
- Text style as {fontFamily, fontWeight, fontSize} objects
- color, state, priority, tagpaths as top-level element properties
- Correct viewBox, meta, position structure

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:36:47 +04:00
48bb43f471 Fix pressure sensor tag path: use _PS suffix, not _PPE
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:30:11 +04:00
0b1f2c0c69 Embed Ignition metadata in SVG export (color, state, priority, tagpath)
Each symbol gets data-* attributes for Ignition integration:
- data-color="#000000", data-state="OFF", data-priority="No Alarms"
- data-tagpath="System/{MCM}/{Category}/{SubType}/{Label}"

Tag paths derived from label suffix (_VFD→VFD/APF, _TPE→Sensor/Tracking, etc.)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 22:28:12 +04:00
053b034a2a Spur label: use same height padding as conveyors for consistent font size
Spur was using availH=h (no padding) giving 14px, while conveyors
used availH=h-4 giving 13px. Now both use the same padding.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:44:08 +04:00
7f9fb6608c Fix spur label clamping: align right edge of text to angled edge
Previous min() was wrong — pushed text further right when text was
wider than available space. Now uses max() to keep text left-aligned
within the trapezoid while right edge stays at the angled boundary.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:43:15 +04:00
07ace0d3f4 Spur label: clamp text right edge to trapezoid boundary
Measure actual text width and position so the right side of the text
aligns with the angled edge of the spur, preventing overflow onto
adjacent conveyors.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:42:36 +04:00
31aea34361 Spur label: compute optimal position from trapezoid geometry
Position text at 55% height (toward wider area), then center
horizontally based on the actual right edge at the text's top,
minimizing overflow past the angled edge.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:41:24 +04:00
f203556082 Spur label: always 14px, never shrink font to fit width
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:39:21 +04:00
9fe6172161 Spur label: position at 90-degree side (x=0 to x=w2 rectangle)
The 90-degree corners are at x=0 in local coords. The rectangular
region from x=0 to x=min(w2,w) always fits inside the trapezoid.
Text is centered in this safe zone — on the straight-edge side,
not the angled side.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:38:41 +04:00
dba857bcc6 Spur label: position at the right-angle corner (65% w, 65% h)
Shift text toward the bottom-right corner of the trapezoid where
the right angle creates the most open space for the label.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:36:53 +04:00
49d426eef3 Spur label: center at midpoint between w2 and w (right half)
Text centered at x = (w2 + w) / 2 — the middle of the wide right
portion of the trapezoid where there's the most space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:36:10 +04:00
9197697129 Remove padding from spur label — wide end has plenty of room
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:35:07 +04:00
ff952c5cb1 Spur label: center at wide end (w/2), keep font at 14px
Place text centered at the wide bottom edge where there's always
enough room. No font shrinking — the wide end has plenty of space.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:34:10 +04:00
3adbfffb9d Spur label: position at 75% height in the wide bottom portion
Center text at 75% of trapezoid height where the shape is widest,
using the actual width at that height for proper fit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:32:23 +04:00
762e65e9a6 Spur label: center at the wide end of the trapezoid
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:31:35 +04:00
35aa0bf7dc Position spur label in the wider area of the trapezoid
Center text at vertical midpoint, shifted right toward the wider end
where there's more horizontal space. Uses 55% of the mid-height width
as center position and 85% as available width.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:31:11 +04:00
6b94339af2 Fix spur label: position at wider end, correct mirrored angle calculation
- Move text to 65% from top (wider end) so it fits without shrinking
- Fix effective angle for mirrored symbols: use (360-rot) to determine
  if flip is needed, preventing incorrect upside-down detection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:28:04 +04:00
072c80e886 Fix spur label sizing: use narrow end width so text fits inside trapezoid
Position text at 40% from top (toward narrow end) and constrain width
to the narrower edge so text never overflows the trapezoid shape.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:26:16 +04:00
3506d6164d Fix spur/mirrored symbol text: counter-mirror so text stays readable
Mirrored symbols need text counter-mirrored (scale -1,1) to prevent
backwards text. Restored mirror fix that was incorrectly removed.
Applied to both canvas renderer and SVG export.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:24:49 +04:00
f6b298254b Use inline style for text bold/font in SVG export (Ignition compat)
Ignition strips font-weight/font-family/font-size as separate SVG
attributes but preserves them inside style="..." CSS. Moved all text
styling to inline style for conveyance labels and BCN/SOL/PDP symbols.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:19:59 +04:00
86f51f2534 Fix BCN/SOL/PDP text centering for Ignition compatibility
Replace dominant-baseline="central" (unsupported in Ignition) with
manual y offset (10 -> 12.8) for proper vertical centering of text
inside these symbol boxes.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:16:34 +04:00
c69d4080fa Mirror labels with their symbols instead of counter-mirroring
Labels now follow the mirrored shape naturally — text mirrors
along with the conveyor/shape as the user expects.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 21:11:01 +04:00