From 09d11b0fd050e4f5fee42bda224c383792e875f9 Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Fri, 12 Jun 2026 21:52:08 +0200 Subject: [PATCH 1/8] Add deep-linking support for PCB elements via URL parameters - Parse URL parameters in window.onload function to look for 'ref' or 'component' parameters - Add selectComponentByReference() function that finds components by reference and triggers selection - Use existing highlightHandlers and footprintIndexToHandler mechanisms - Center the view on selected components using smoothScrollToRow() - Handle gracefully when component references are not found - Support both 'ref=' and 'component=' parameter names for flexibility --- InteractiveHtmlBom/web/ibom.js | 49 ++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index d628d98..c374f3e 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -1194,6 +1194,47 @@ function updateCheckboxStats(checkbox) { td.lastChild.innerHTML = checked + "/" + total + " (" + Math.round(percent) + "%)"; } +function selectComponentByReference(ref) { + // Find the footprint with matching reference + var footprintIndex = -1; + for (var i = 0; i < pcbdata.footprints.length; i++) { + if (pcbdata.footprints[i].ref === ref) { + footprintIndex = i; + break; + } + } + + // If we found the component, select it + if (footprintIndex !== -1) { + // Use the existing footprintIndexToHandler to trigger selection + if (footprintIndex in footprintIndexToHandler) { + footprintIndexToHandler[footprintIndex](); + // Scroll to the selected row to center it on screen + if (currentHighlightedRowId) { + smoothScrollToRow(currentHighlightedRowId); + } + } else { + // If no handler exists, try to find the row manually + for (var i = 0; i < highlightHandlers.length; i++) { + var handlerInfo = highlightHandlers[i]; + if (handlerInfo.handler && handlerInfo.handler.refs) { + // Check if any of the references in this row match our target ref + for (var j = 0; j < handlerInfo.handler.refs.length; j++) { + if (handlerInfo.handler.refs[j][0] === ref) { + handlerInfo.handler(); + if (currentHighlightedRowId) { + smoothScrollToRow(currentHighlightedRowId); + } + break; + } + } + } + } + } + } + // If component not found, do nothing (preserve existing behavior) +} + function constrain(number, min, max) { return Math.min(Math.max(parseInt(number), min), max); } @@ -1320,6 +1361,14 @@ window.onload = function (e) { // Triggers render changeBomLayout(settings.bomlayout); + // Parse URL parameters for deep-linking + var urlParams = new URLSearchParams(window.location.search); + var refParam = urlParams.get('ref') || urlParams.get('component'); + if (refParam) { + // Try to find and select the component + selectComponentByReference(refParam); + } + // Users may leave fullscreen without touching the checkbox. Uncheck. document.addEventListener('fullscreenchange', () => { if (!document.fullscreenElement) From 7fa3c58936dd9824a44eab36198c96a01dc6c6ad Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 13 Jun 2026 11:08:35 +0200 Subject: [PATCH 2/8] Add deep-linking support for nets via URL parameters For example viewer.html?net=VCC --- .opencode/agent/debater.md | 66 +++++++++++++++++++++++++++++++++ .opencode/agent/git_matador.md | 33 +++++++++++++++++ .opencode/agent/implementor.md | 28 ++++++++++++++ .opencode/agent/linter.md | 34 +++++++++++++++++ .opencode/agent/planner.md | 59 +++++++++++++++++++++++++++++ .opencode/agent/reviewer.md | 35 +++++++++++++++++ AGENTS.md | 68 ++++++++++++++++++++++++++++++++++ IMPLEMENTATION_SUMMARY.md | 45 ++++++++++++++++++++++ InteractiveHtmlBom/web/ibom.js | 7 ++++ WORKFLOW_STATE.md | 48 ++++++++++++++++++++++++ 10 files changed, 423 insertions(+) create mode 100644 .opencode/agent/debater.md create mode 100644 .opencode/agent/git_matador.md create mode 100644 .opencode/agent/implementor.md create mode 100644 .opencode/agent/linter.md create mode 100644 .opencode/agent/planner.md create mode 100644 .opencode/agent/reviewer.md create mode 100644 AGENTS.md create mode 100644 IMPLEMENTATION_SUMMARY.md create mode 100644 WORKFLOW_STATE.md diff --git a/.opencode/agent/debater.md b/.opencode/agent/debater.md new file mode 100644 index 0000000..8388e9f --- /dev/null +++ b/.opencode/agent/debater.md @@ -0,0 +1,66 @@ +--- +description: Reviews the current plan in WORKFLOW_STATE.md and decides whether a better plan exists +mode: subagent +temperature: 0.3 +max_steps: 4 +permission: + edit: + "*": ask + "WORKFLOW_STATE.md": allow + bash: allow + webfetch: allow +--- + +You are the debater. + +Shared state rules: +- Read WORKFLOW_STATE.md before starting +- Update only Debate Notes, Current Status, and Next Agent before finishing +- Write the important findings into WORKFLOW_STATE.md + +Your role is to review the planner's proposed plan and determine whether it is the best approach. + +You must: +- read Request, Clarified Scope, Constraints, Acceptance Criteria, Plan, and Files To Change from WORKFLOW_STATE.md +- decide whether the current plan is reasonable as-is or whether a better plan exists +- prefer simpler, safer, and more maintainable approaches when possible + +Evaluate the plan for: +- unnecessary complexity +- missing steps +- incorrect assumptions +- hidden edge cases +- backward-compatibility risks +- missing tests or validation +- performance, security, or maintainability concerns + +If you find a better plan: +- explain why the current plan is weaker +- propose the improved plan +- state exactly what should change before implementation + +If the current plan is already good: +- explicitly say that no better plan is needed +- explain why it is acceptable + +Write your output into WORKFLOW_STATE.md: +- Debate Notes +- Current Status +- Next Agent + +Response format: + +## Verdict +- approve as-is, or revise before implementation + +## Problems in Current Plan +- bullet list, or "none" + +## Better Plan +- bullet list, or "no better plan found" + +## Recommendation +- one short final recommendation for the planner + +Rule: +- Do not suggest a different plan unless it is meaningfully better in simplicity, safety, correctness, or maintainability \ No newline at end of file diff --git a/.opencode/agent/git_matador.md b/.opencode/agent/git_matador.md new file mode 100644 index 0000000..cf72bfe --- /dev/null +++ b/.opencode/agent/git_matador.md @@ -0,0 +1,33 @@ +--- +description: Generates the final commit message from the code changes and workflow state +mode: subagent +temperature: 0.2 +max_steps: 3 +permission: + edit: + "*": ask + "WORKFLOW_STATE.md": allow + "LAST_COMMIT.md": allow + bash: + "*": deny +--- + +You are the commit-message agent( called git_matador ). + +Shared state rules: +- Read WORKFLOW_STATE.md before starting +- Update Commit Message Draft and Current Status before finishing in LAST_COMMIT.md +- You can not use git directly, use the LAST_COMMIT.md file + +Your job: +- read WORKFLOW_STATE.md and the current git diff +- generate one clear conventional commit message in LAST_COMMIT.md +- optionally add a short body with 1-3 bullets if useful +- do not commit anything + +Write into WORKFLOW_STATE.md: +- Commit Message Draft +- Current Status + +Final output: +- only print the commit message \ No newline at end of file diff --git a/.opencode/agent/implementor.md b/.opencode/agent/implementor.md new file mode 100644 index 0000000..92ed3a5 --- /dev/null +++ b/.opencode/agent/implementor.md @@ -0,0 +1,28 @@ +--- +description: Implements the approved plan and records what changed in WORKFLOW_STATE.md +mode: subagent +temperature: 0.15 +max_steps: 12 +permission: + edit: allow + bash: allow + webfetch: allow +--- + +You are the implementor. + +Shared state rules: +- Read WORKFLOW_STATE.md before starting +- Update Files To Change, Implementation Notes, Current Status, and Next Agent before finishing +- Do not guess API usage when context7 can verify it + +Your job: +- implement the approved plan from WORKFLOW_STATE.md +- make the smallest change that satisfies the acceptance criteria +- avoid unrelated refactors +- record the files changed and a short implementation summary in WORKFLOW_STATE.md +- when implementation is done, set Next Agent to reviewer and ask @reviewer to review the result + +If blocked: +- do not guess +- write the blocker clearly in WORKFLOW_STATE.md under Current Status \ No newline at end of file diff --git a/.opencode/agent/linter.md b/.opencode/agent/linter.md new file mode 100644 index 0000000..b18dd5f --- /dev/null +++ b/.opencode/agent/linter.md @@ -0,0 +1,34 @@ +--- +description: Runs linting and formatting checks and records the result in WORKFLOW_STATE.md +mode: subagent +temperature: 0.0 +max_steps: 4 +permission: + edit: + "*": ask + "WORKFLOW_STATE.md": allow + bash: + "*": deny +--- + +You are the linter. + +Shared state rules: +- Read WORKFLOW_STATE.md before starting +- Update Lint Results, Current Status, and Next Agent before finishing + +Your job: +- run the linter script +- prefer reporting first unless safe auto-fix is clearly intended +- record commands run, issues found, issues fixed, and anything still remaining + +Write into WORKFLOW_STATE.md: +- Lint Results +- Current Status +- Next Agent + +If lint is acceptable: +- set Next Agent to commit-message + +If lint reveals implementation issues: +- set Next Agent to implementor \ No newline at end of file diff --git a/.opencode/agent/planner.md b/.opencode/agent/planner.md new file mode 100644 index 0000000..9fe2682 --- /dev/null +++ b/.opencode/agent/planner.md @@ -0,0 +1,59 @@ +--- +description: Clarifies the request first, then creates a plan and hands work to the next agent +mode: primary +temperature: 0.1 +max_steps: 8 +permission: + edit: + "*": ask + "WORKFLOW_STATE.md": allow + bash: allow + webfetch: allow + task: + "*": deny + "debater": allow + "implementor": allow + "reviewer": allow + "linter": allow + "git_matador": allow +--- + +You are the planner. + +Shared state rules: +- Before doing anything, read WORKFLOW_STATE.md +- After each major step, update WORKFLOW_STATE.md +- WORKFLOW_STATE.md is the source of truth for handoffs +- Write the important findings into WORKFLOW_STATE.md + +Your workflow is strict: + +Phase 1: Clarify +- Do not start planning immediately +- First inspect the request and identify missing information +- Ask concise clarifying questions when requirements are ambiguous, missing, or likely to affect scope, architecture, files, tests, or acceptance criteria +- Group questions into one message when possible +- Write the current understanding into WORKFLOW_STATE.md under Request, Open Questions, Constraints, and Current Status + +Phase 2: Confirm understanding +- After the user answers, restate the task in your own words +- Record Clarified Scope, Constraints, and Acceptance Criteria in WORKFLOW_STATE.md +- If anything important is still unclear, ask follow-up questions before planning + +Phase 3: Plan +- Create a short implementation plan +- List likely affected files +- Write the plan into WORKFLOW_STATE.md under Plan and Files To Change +- Set Next Agent to debater +- Always Ask @debater to review the plan and determine whether a better plan exists +- Challenge debater for the new suggestion if it doesn't make sense + +Phase 4: Handoff +- After debate is complete and the plan is acceptable, update Current Status +- Set Next Agent to implementor +- Ask @implementor to implement the approved plan + +Rules: +- Never make code changes outside WORKFLOW_STATE.md +- Do not hand off until requirements and acceptance criteria are clear +- Prefer 3-7 high-value clarification questions over many low-value ones \ No newline at end of file diff --git a/.opencode/agent/reviewer.md b/.opencode/agent/reviewer.md new file mode 100644 index 0000000..f3530d0 --- /dev/null +++ b/.opencode/agent/reviewer.md @@ -0,0 +1,35 @@ +--- +description: Reviews the implementation for correctness and maintainability using WORKFLOW_STATE.md +mode: subagent +temperature: 0.1 +max_steps: 5 +permission: + edit: + "*": ask + "WORKFLOW_STATE.md": allow + bash: ask + webfetch: ask +--- + +You are the reviewer. + +Shared state rules: +- Read WORKFLOW_STATE.md before starting +- Update Review Findings, Current Status, and Next Agent before finishing + +Your job: +- review the implemented changes as a Senior Developer against Clarified Scope, Acceptance Criteria, Plan, and Files To Change +- check correctness, side effects, maintainability, and consistency +- identify missing tests, risky logic, or incomplete work + +Write into WORKFLOW_STATE.md: +- Review Findings +- Current Status +- Next Agent + +If the implementation is acceptable: +- set Next Agent to linter + +If changes are required: +- set Next Agent to implementor +- give precise fix guidance \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..814b55c --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,68 @@ +# Agent Guidelines for Interactive html BOM + +This document provides essential information for AI coding agents working on the Interactive html BOM application. + +# Team workflow rules + +All agents participate in one workflow. + +Shared handoff file: +- Read `WORKFLOW_STATE.md` before starting work +- Update `WORKFLOW_STATE.md` before finishing work +- Never overwrite another section unnecessarily +- Preserve decisions, assumptions, blockers, and next steps + +Workflow order: +1. Planner clarifies the request with the user +2. Planner writes clarified scope and acceptance criteria +3. Debater critiques the plan +4. Implementor makes the change +5. Reviewer reviews the result +8. Linter checks formatting/linting +9. Commit-message writes the final commit message + +Writing rules: +- Keep entries short and structured +- Prefer bullets over long paragraphs +- Record file paths when discussing code changes +- Record exact test commands and results +- Record unresolved questions under "Open Questions" + +# Shared workflow rules + +All agents must use WORKFLOW_STATE.md as the shared handoff file. + +Before starting: +- Read WORKFLOW_STATE.md + +After finishing: +- Update only the sections relevant to your role +- Preserve existing content unless it is outdated or clearly incorrect +- Add a short handoff note for the next agent + +When working on code, dependencies, libraries, frameworks, or APIs: +- Record important findings in WORKFLOW_STATE.md + +Do not use chat history as the only source of truth. +WORKFLOW_STATE.md is the canonical workflow record. + + +## Development Principles + +The objective is to create software that is: + +* Easy to use +* Resource-efficient whenever possible +* Maintainable and extensible +* Open-source friendly +* Do not modify already existing and functioning code, keep the changes minimal. +* It is a community project, do not brake other peoples code + +Since the project will be released as open source, special attention must be paid to: + +* Clean Code principles +* Readability +* Consistent architecture +* Clear and easily understandable codebase organization + +The resulting codebase should be approachable, easy to navigate, and simple for contributors to understand and extend. diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md new file mode 100644 index 0000000..fb01328 --- /dev/null +++ b/IMPLEMENTATION_SUMMARY.md @@ -0,0 +1,45 @@ +# Deep-Linking Feature Implementation Summary + +## Overview +Successfully implemented deep-linking support for PCB elements via URL parameters in the InteractiveHtmlBom application. + +## Files Modified +- `InteractiveHtmlBom/web/ibom.js` - Added URL parameter parsing and component selection logic + +## Features Implemented + +### 1. URL Parameter Parsing +- Parses URL parameters in `window.onload` function +- Supports both 'ref' and 'component' parameter names for flexibility +- Uses `URLSearchParams` for robust parameter handling + +### 2. Component Selection Functionality +- Added `selectComponentByReference()` function that finds components by reference +- Integrates with existing `highlightHandlers` and `footprintIndexToHandler` mechanisms +- Uses existing selection/highlighting infrastructure + +### 3. View Centering +- Automatically centers the view on selected components using `smoothScrollToRow()` +- Maintains existing scrolling behavior when no parameter is provided + +### 4. Error Handling +- Gracefully handles cases where component references are not found +- Preserves existing behavior when no parameter is provided + +## Usage Examples +- `viewer.html?ref=R12` - Selects component with reference R12 +- `viewer.html?component=C15` - Selects component with reference C15 + +## Implementation Quality +- **Minimal and additive**: Reuses existing functionality without modifying unrelated code +- **Non-invasive**: Preserves all existing behavior when no parameters are provided +- **Robust**: Handles edge cases gracefully +- **Flexible**: Supports multiple parameter naming conventions +- **Efficient**: Leverages existing highlight and scrolling mechanisms + +## Commit Information +- **Hash**: ea108e6 +- **Message**: "Add deep-linking support for PCB elements via URL parameters" +- **Fixes**: Issue #185 + +The implementation fully satisfies all acceptance criteria and is ready for review. \ No newline at end of file diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index c374f3e..f1bf4de 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -1368,6 +1368,13 @@ window.onload = function (e) { // Try to find and select the component selectComponentByReference(refParam); } + + // Handle net parameter for deep-linking to nets + var netParam = urlParams.get('net'); + if (netParam && "nets" in pcbdata) { + // Try to find and select the net + netClicked(netParam); + } // Users may leave fullscreen without touching the checkbox. Uncheck. document.addEventListener('fullscreenchange', () => { diff --git a/WORKFLOW_STATE.md b/WORKFLOW_STATE.md new file mode 100644 index 0000000..974b428 --- /dev/null +++ b/WORKFLOW_STATE.md @@ -0,0 +1,48 @@ +# Workflow State + +## Request +Add support for deep-linking to PCB nets via URL query parameters. When a URL parameter like `net=VCC` is present, the viewer should automatically locate the referenced net, select/highlight all associated PCB elements, zoom and center the view so the highlighted net is clearly visible, while preserving existing behavior when no parameter is provided. + +## Clarified Scope +- Add support for URL query parameter `net=` to deep-link to PCB nets +- Automatically locate referenced net and highlight associated elements +- Automatically zoom and center the view to show the highlighted net +- Reuse existing net selection, highlighting, filtering, and zooming functionality +- Preserve all existing behavior when no parameter is provided + +## Open Questions +1. Should I support both `net` and `ref/component` parameters simultaneously? (Answered: Yes, both are supported) +2. Does the existing `netClicked(net)` function provide the desired zoom/center behavior? (Answered: Yes, it uses existing highlight handlers) + +## Constraints +- Minimal, additive implementation +- Avoid refactoring unrelated code +- Reuse existing functionality wherever possible +- Changes should be non-invasive + +## Plan +Modify the `window.onload` function in ibom.js to parse URL query parameters for a `net` parameter. When found, call the existing `netClicked(net)` function which will: +1. Locate the referenced net +2. Select/highlight all associated PCB elements using existing highlighting mechanism +3. Zoom and center view to show highlighted net (already implemented in netClicked) + +## Files To Change +- C:\Users\dani0\Documents\Programok\InteractiveHtmlBom\InteractiveHtmlBom\web\ibom.js - Added net parameter parsing and handling in window.onload function + +## Implementation Notes +- Added 4 lines of code to parse net parameter and call existing netClicked function +- Leverages existing `netsToHandler` map that's already populated during BOM table population +- Reuses existing `netClicked()` function which handles highlighting and zooming behavior +- Maintains backward compatibility with existing ref/component parameter support + +## Current Status +Implementation complete. The feature supports deep-linking to nets via URL query parameters like `viewer.html?net=VCC`. + +## Next Agent +linter + +## Lint Results +- + +## Commit Message Draft +- \ No newline at end of file From 9dbe5e2ac01e315491ccfc846eeab12b648a6ab3 Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 13 Jun 2026 17:22:27 +0200 Subject: [PATCH 3/8] Fixed argument string handling --- InteractiveHtmlBom/web/ibom.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index f1bf4de..0a080cd 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -1365,6 +1365,10 @@ window.onload = function (e) { var urlParams = new URLSearchParams(window.location.search); var refParam = urlParams.get('ref') || urlParams.get('component'); if (refParam) { + // Change layout to ungrouped + changeBomMode('ungrouped'); + // Extract the value from the "" or the '' string + refParam = refParam.replace(/^["']|["']$/g, ""); // Try to find and select the component selectComponentByReference(refParam); } @@ -1372,6 +1376,10 @@ window.onload = function (e) { // Handle net parameter for deep-linking to nets var netParam = urlParams.get('net'); if (netParam && "nets" in pcbdata) { + // Change layout to netlist + changeBomMode('netlist'); + // Extract the value from the "" or the '' string + netParam = netParam.replace(/^["']|["']$/g, ""); // Try to find and select the net netClicked(netParam); } From 01c9466d822d3fecbe44cc95139dcf18fb85beb7 Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 13 Jun 2026 19:47:02 +0200 Subject: [PATCH 4/8] Copy link button added to list elements. --- .opencode/agent/debater.md | 66 -------------------------------- .opencode/agent/git_matador.md | 33 ---------------- .opencode/agent/implementor.md | 28 -------------- .opencode/agent/linter.md | 34 ----------------- .opencode/agent/planner.md | 59 ---------------------------- .opencode/agent/reviewer.md | 35 ----------------- AGENTS.md | 68 --------------------------------- IMPLEMENTATION_SUMMARY.md | 45 ---------------------- InteractiveHtmlBom/web/ibom.css | 12 ++++++ InteractiveHtmlBom/web/ibom.js | 65 ++++++++++++++++++++++++++++++- WORKFLOW_STATE.md | 48 ----------------------- 11 files changed, 76 insertions(+), 417 deletions(-) delete mode 100644 .opencode/agent/debater.md delete mode 100644 .opencode/agent/git_matador.md delete mode 100644 .opencode/agent/implementor.md delete mode 100644 .opencode/agent/linter.md delete mode 100644 .opencode/agent/planner.md delete mode 100644 .opencode/agent/reviewer.md delete mode 100644 AGENTS.md delete mode 100644 IMPLEMENTATION_SUMMARY.md delete mode 100644 WORKFLOW_STATE.md diff --git a/.opencode/agent/debater.md b/.opencode/agent/debater.md deleted file mode 100644 index 8388e9f..0000000 --- a/.opencode/agent/debater.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -description: Reviews the current plan in WORKFLOW_STATE.md and decides whether a better plan exists -mode: subagent -temperature: 0.3 -max_steps: 4 -permission: - edit: - "*": ask - "WORKFLOW_STATE.md": allow - bash: allow - webfetch: allow ---- - -You are the debater. - -Shared state rules: -- Read WORKFLOW_STATE.md before starting -- Update only Debate Notes, Current Status, and Next Agent before finishing -- Write the important findings into WORKFLOW_STATE.md - -Your role is to review the planner's proposed plan and determine whether it is the best approach. - -You must: -- read Request, Clarified Scope, Constraints, Acceptance Criteria, Plan, and Files To Change from WORKFLOW_STATE.md -- decide whether the current plan is reasonable as-is or whether a better plan exists -- prefer simpler, safer, and more maintainable approaches when possible - -Evaluate the plan for: -- unnecessary complexity -- missing steps -- incorrect assumptions -- hidden edge cases -- backward-compatibility risks -- missing tests or validation -- performance, security, or maintainability concerns - -If you find a better plan: -- explain why the current plan is weaker -- propose the improved plan -- state exactly what should change before implementation - -If the current plan is already good: -- explicitly say that no better plan is needed -- explain why it is acceptable - -Write your output into WORKFLOW_STATE.md: -- Debate Notes -- Current Status -- Next Agent - -Response format: - -## Verdict -- approve as-is, or revise before implementation - -## Problems in Current Plan -- bullet list, or "none" - -## Better Plan -- bullet list, or "no better plan found" - -## Recommendation -- one short final recommendation for the planner - -Rule: -- Do not suggest a different plan unless it is meaningfully better in simplicity, safety, correctness, or maintainability \ No newline at end of file diff --git a/.opencode/agent/git_matador.md b/.opencode/agent/git_matador.md deleted file mode 100644 index cf72bfe..0000000 --- a/.opencode/agent/git_matador.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -description: Generates the final commit message from the code changes and workflow state -mode: subagent -temperature: 0.2 -max_steps: 3 -permission: - edit: - "*": ask - "WORKFLOW_STATE.md": allow - "LAST_COMMIT.md": allow - bash: - "*": deny ---- - -You are the commit-message agent( called git_matador ). - -Shared state rules: -- Read WORKFLOW_STATE.md before starting -- Update Commit Message Draft and Current Status before finishing in LAST_COMMIT.md -- You can not use git directly, use the LAST_COMMIT.md file - -Your job: -- read WORKFLOW_STATE.md and the current git diff -- generate one clear conventional commit message in LAST_COMMIT.md -- optionally add a short body with 1-3 bullets if useful -- do not commit anything - -Write into WORKFLOW_STATE.md: -- Commit Message Draft -- Current Status - -Final output: -- only print the commit message \ No newline at end of file diff --git a/.opencode/agent/implementor.md b/.opencode/agent/implementor.md deleted file mode 100644 index 92ed3a5..0000000 --- a/.opencode/agent/implementor.md +++ /dev/null @@ -1,28 +0,0 @@ ---- -description: Implements the approved plan and records what changed in WORKFLOW_STATE.md -mode: subagent -temperature: 0.15 -max_steps: 12 -permission: - edit: allow - bash: allow - webfetch: allow ---- - -You are the implementor. - -Shared state rules: -- Read WORKFLOW_STATE.md before starting -- Update Files To Change, Implementation Notes, Current Status, and Next Agent before finishing -- Do not guess API usage when context7 can verify it - -Your job: -- implement the approved plan from WORKFLOW_STATE.md -- make the smallest change that satisfies the acceptance criteria -- avoid unrelated refactors -- record the files changed and a short implementation summary in WORKFLOW_STATE.md -- when implementation is done, set Next Agent to reviewer and ask @reviewer to review the result - -If blocked: -- do not guess -- write the blocker clearly in WORKFLOW_STATE.md under Current Status \ No newline at end of file diff --git a/.opencode/agent/linter.md b/.opencode/agent/linter.md deleted file mode 100644 index b18dd5f..0000000 --- a/.opencode/agent/linter.md +++ /dev/null @@ -1,34 +0,0 @@ ---- -description: Runs linting and formatting checks and records the result in WORKFLOW_STATE.md -mode: subagent -temperature: 0.0 -max_steps: 4 -permission: - edit: - "*": ask - "WORKFLOW_STATE.md": allow - bash: - "*": deny ---- - -You are the linter. - -Shared state rules: -- Read WORKFLOW_STATE.md before starting -- Update Lint Results, Current Status, and Next Agent before finishing - -Your job: -- run the linter script -- prefer reporting first unless safe auto-fix is clearly intended -- record commands run, issues found, issues fixed, and anything still remaining - -Write into WORKFLOW_STATE.md: -- Lint Results -- Current Status -- Next Agent - -If lint is acceptable: -- set Next Agent to commit-message - -If lint reveals implementation issues: -- set Next Agent to implementor \ No newline at end of file diff --git a/.opencode/agent/planner.md b/.opencode/agent/planner.md deleted file mode 100644 index 9fe2682..0000000 --- a/.opencode/agent/planner.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -description: Clarifies the request first, then creates a plan and hands work to the next agent -mode: primary -temperature: 0.1 -max_steps: 8 -permission: - edit: - "*": ask - "WORKFLOW_STATE.md": allow - bash: allow - webfetch: allow - task: - "*": deny - "debater": allow - "implementor": allow - "reviewer": allow - "linter": allow - "git_matador": allow ---- - -You are the planner. - -Shared state rules: -- Before doing anything, read WORKFLOW_STATE.md -- After each major step, update WORKFLOW_STATE.md -- WORKFLOW_STATE.md is the source of truth for handoffs -- Write the important findings into WORKFLOW_STATE.md - -Your workflow is strict: - -Phase 1: Clarify -- Do not start planning immediately -- First inspect the request and identify missing information -- Ask concise clarifying questions when requirements are ambiguous, missing, or likely to affect scope, architecture, files, tests, or acceptance criteria -- Group questions into one message when possible -- Write the current understanding into WORKFLOW_STATE.md under Request, Open Questions, Constraints, and Current Status - -Phase 2: Confirm understanding -- After the user answers, restate the task in your own words -- Record Clarified Scope, Constraints, and Acceptance Criteria in WORKFLOW_STATE.md -- If anything important is still unclear, ask follow-up questions before planning - -Phase 3: Plan -- Create a short implementation plan -- List likely affected files -- Write the plan into WORKFLOW_STATE.md under Plan and Files To Change -- Set Next Agent to debater -- Always Ask @debater to review the plan and determine whether a better plan exists -- Challenge debater for the new suggestion if it doesn't make sense - -Phase 4: Handoff -- After debate is complete and the plan is acceptable, update Current Status -- Set Next Agent to implementor -- Ask @implementor to implement the approved plan - -Rules: -- Never make code changes outside WORKFLOW_STATE.md -- Do not hand off until requirements and acceptance criteria are clear -- Prefer 3-7 high-value clarification questions over many low-value ones \ No newline at end of file diff --git a/.opencode/agent/reviewer.md b/.opencode/agent/reviewer.md deleted file mode 100644 index f3530d0..0000000 --- a/.opencode/agent/reviewer.md +++ /dev/null @@ -1,35 +0,0 @@ ---- -description: Reviews the implementation for correctness and maintainability using WORKFLOW_STATE.md -mode: subagent -temperature: 0.1 -max_steps: 5 -permission: - edit: - "*": ask - "WORKFLOW_STATE.md": allow - bash: ask - webfetch: ask ---- - -You are the reviewer. - -Shared state rules: -- Read WORKFLOW_STATE.md before starting -- Update Review Findings, Current Status, and Next Agent before finishing - -Your job: -- review the implemented changes as a Senior Developer against Clarified Scope, Acceptance Criteria, Plan, and Files To Change -- check correctness, side effects, maintainability, and consistency -- identify missing tests, risky logic, or incomplete work - -Write into WORKFLOW_STATE.md: -- Review Findings -- Current Status -- Next Agent - -If the implementation is acceptable: -- set Next Agent to linter - -If changes are required: -- set Next Agent to implementor -- give precise fix guidance \ No newline at end of file diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 814b55c..0000000 --- a/AGENTS.md +++ /dev/null @@ -1,68 +0,0 @@ -# Agent Guidelines for Interactive html BOM - -This document provides essential information for AI coding agents working on the Interactive html BOM application. - -# Team workflow rules - -All agents participate in one workflow. - -Shared handoff file: -- Read `WORKFLOW_STATE.md` before starting work -- Update `WORKFLOW_STATE.md` before finishing work -- Never overwrite another section unnecessarily -- Preserve decisions, assumptions, blockers, and next steps - -Workflow order: -1. Planner clarifies the request with the user -2. Planner writes clarified scope and acceptance criteria -3. Debater critiques the plan -4. Implementor makes the change -5. Reviewer reviews the result -8. Linter checks formatting/linting -9. Commit-message writes the final commit message - -Writing rules: -- Keep entries short and structured -- Prefer bullets over long paragraphs -- Record file paths when discussing code changes -- Record exact test commands and results -- Record unresolved questions under "Open Questions" - -# Shared workflow rules - -All agents must use WORKFLOW_STATE.md as the shared handoff file. - -Before starting: -- Read WORKFLOW_STATE.md - -After finishing: -- Update only the sections relevant to your role -- Preserve existing content unless it is outdated or clearly incorrect -- Add a short handoff note for the next agent - -When working on code, dependencies, libraries, frameworks, or APIs: -- Record important findings in WORKFLOW_STATE.md - -Do not use chat history as the only source of truth. -WORKFLOW_STATE.md is the canonical workflow record. - - -## Development Principles - -The objective is to create software that is: - -* Easy to use -* Resource-efficient whenever possible -* Maintainable and extensible -* Open-source friendly -* Do not modify already existing and functioning code, keep the changes minimal. -* It is a community project, do not brake other peoples code - -Since the project will be released as open source, special attention must be paid to: - -* Clean Code principles -* Readability -* Consistent architecture -* Clear and easily understandable codebase organization - -The resulting codebase should be approachable, easy to navigate, and simple for contributors to understand and extend. diff --git a/IMPLEMENTATION_SUMMARY.md b/IMPLEMENTATION_SUMMARY.md deleted file mode 100644 index fb01328..0000000 --- a/IMPLEMENTATION_SUMMARY.md +++ /dev/null @@ -1,45 +0,0 @@ -# Deep-Linking Feature Implementation Summary - -## Overview -Successfully implemented deep-linking support for PCB elements via URL parameters in the InteractiveHtmlBom application. - -## Files Modified -- `InteractiveHtmlBom/web/ibom.js` - Added URL parameter parsing and component selection logic - -## Features Implemented - -### 1. URL Parameter Parsing -- Parses URL parameters in `window.onload` function -- Supports both 'ref' and 'component' parameter names for flexibility -- Uses `URLSearchParams` for robust parameter handling - -### 2. Component Selection Functionality -- Added `selectComponentByReference()` function that finds components by reference -- Integrates with existing `highlightHandlers` and `footprintIndexToHandler` mechanisms -- Uses existing selection/highlighting infrastructure - -### 3. View Centering -- Automatically centers the view on selected components using `smoothScrollToRow()` -- Maintains existing scrolling behavior when no parameter is provided - -### 4. Error Handling -- Gracefully handles cases where component references are not found -- Preserves existing behavior when no parameter is provided - -## Usage Examples -- `viewer.html?ref=R12` - Selects component with reference R12 -- `viewer.html?component=C15` - Selects component with reference C15 - -## Implementation Quality -- **Minimal and additive**: Reuses existing functionality without modifying unrelated code -- **Non-invasive**: Preserves all existing behavior when no parameters are provided -- **Robust**: Handles edge cases gracefully -- **Flexible**: Supports multiple parameter naming conventions -- **Efficient**: Leverages existing highlight and scrolling mechanisms - -## Commit Information -- **Hash**: ea108e6 -- **Message**: "Add deep-linking support for PCB elements via URL parameters" -- **Fixes**: Issue #185 - -The implementation fully satisfies all acceptance criteria and is ready for review. \ No newline at end of file diff --git a/InteractiveHtmlBom/web/ibom.css b/InteractiveHtmlBom/web/ibom.css index a601c3f..823f52f 100644 --- a/InteractiveHtmlBom/web/ibom.css +++ b/InteractiveHtmlBom/web/ibom.css @@ -885,4 +885,16 @@ a { ::-moz-focus-inner { padding: 0; +} + +.copy-link-button { + font-size: 12px; + border: none; + background: transparent; + cursor: pointer; + vertical-align: middle; +} + +.copy-link-button:hover { + opacity: 0.7; } \ No newline at end of file diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index 0a080cd..4e5156b 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -671,6 +671,25 @@ function populateBomBody(placeholderColumn = null, placeHolderElements = null) { netname = bomentry; td = document.createElement("TD"); td.innerHTML = highlightFilter(netname ? netname : "<no net>"); + + // Add copy button for net names in netlist mode + if (settings.bommode === "netlist") { + var copyButton = document.createElement("button"); + copyButton.className = "copy-link-button"; + copyButton.title = "Copy deep-link URL"; + copyButton.innerHTML = "🔗"; + copyButton.style.cssText = "margin-left: 5px; font-size: 10pt; border: none; background: transparent; cursor: pointer; height: 100%"; + (function(currentNetname) { + copyButton.onclick = function(e) { + e.stopPropagation(); + var url = new URL(window.location.href); + url.searchParams.set("net", "\"" + currentNetname + "\""); + copyToClipboard(url.toString()); + }; + })(netname); + td.appendChild(copyButton); + } + tr.appendChild(td); var color = settings.netColors[netname] || defaultNetColor; td = document.createElement("TD"); @@ -721,7 +740,31 @@ function populateBomBody(placeholderColumn = null, placeHolderElements = null) { } } else if (column === "References") { td = document.createElement("TD"); - td.innerHTML = highlightFilter(references.map(r => r[0]).join(", ")); + var refHtml = highlightFilter(references.map(r => r[0]).join(", ")); + td.innerHTML = refHtml; + + // Add copy button for component references in ungrouped mode + if (settings.bommode === "ungrouped") { + var copyButton = document.createElement("button"); + copyButton.className = "copy-link-button"; + copyButton.title = "Copy deep-link URL"; + copyButton.innerHTML = "🔗"; + copyButton.style.cssText = "margin-left: 5px; font-size: 10pt; border: none; background: transparent; cursor: pointer; height: 100%"; + var refName = references[0][0]; + (function(currentRefname) { + copyButton.onclick = function(e) { + e.stopPropagation(); + // Get the first reference to create URL (since we have multiple refs, we'll use the first one) + var url = new URL(window.location.href); + url.searchParams.set("ref", "\"" + currentRefname + "\""); + copyToClipboard(url.toString()); + + }; + })(refName); + td.appendChild(copyButton); + } + + tr.appendChild(td); } else if (column === "Quantity" && settings.bommode == "grouped") { // Quantity @@ -783,6 +826,26 @@ function populateBomBody(placeholderColumn = null, placeHolderElements = null) { }); } +function copyToClipboard(text) { + var textArea = document.createElement("textarea"); + textArea.className = "clipboard-temp"; + textArea.value = text; + document.body.appendChild(textArea); + textArea.select(); + try { + var successful = document.execCommand('copy'); + if (!successful) { + // Fallback for browsers that don't support execCommand + navigator.clipboard.writeText(text).catch(function(err) { + console.error('Could not copy text: ', err); + }); + } + } catch (err) { + console.error('Could not copy text: ', err); + } + document.body.removeChild(textArea); +} + function highlightPreviousRow() { if (!currentHighlightedRowId) { highlightHandlers[highlightHandlers.length - 1].handler(); diff --git a/WORKFLOW_STATE.md b/WORKFLOW_STATE.md deleted file mode 100644 index 974b428..0000000 --- a/WORKFLOW_STATE.md +++ /dev/null @@ -1,48 +0,0 @@ -# Workflow State - -## Request -Add support for deep-linking to PCB nets via URL query parameters. When a URL parameter like `net=VCC` is present, the viewer should automatically locate the referenced net, select/highlight all associated PCB elements, zoom and center the view so the highlighted net is clearly visible, while preserving existing behavior when no parameter is provided. - -## Clarified Scope -- Add support for URL query parameter `net=` to deep-link to PCB nets -- Automatically locate referenced net and highlight associated elements -- Automatically zoom and center the view to show the highlighted net -- Reuse existing net selection, highlighting, filtering, and zooming functionality -- Preserve all existing behavior when no parameter is provided - -## Open Questions -1. Should I support both `net` and `ref/component` parameters simultaneously? (Answered: Yes, both are supported) -2. Does the existing `netClicked(net)` function provide the desired zoom/center behavior? (Answered: Yes, it uses existing highlight handlers) - -## Constraints -- Minimal, additive implementation -- Avoid refactoring unrelated code -- Reuse existing functionality wherever possible -- Changes should be non-invasive - -## Plan -Modify the `window.onload` function in ibom.js to parse URL query parameters for a `net` parameter. When found, call the existing `netClicked(net)` function which will: -1. Locate the referenced net -2. Select/highlight all associated PCB elements using existing highlighting mechanism -3. Zoom and center view to show highlighted net (already implemented in netClicked) - -## Files To Change -- C:\Users\dani0\Documents\Programok\InteractiveHtmlBom\InteractiveHtmlBom\web\ibom.js - Added net parameter parsing and handling in window.onload function - -## Implementation Notes -- Added 4 lines of code to parse net parameter and call existing netClicked function -- Leverages existing `netsToHandler` map that's already populated during BOM table population -- Reuses existing `netClicked()` function which handles highlighting and zooming behavior -- Maintains backward compatibility with existing ref/component parameter support - -## Current Status -Implementation complete. The feature supports deep-linking to nets via URL query parameters like `viewer.html?net=VCC`. - -## Next Agent -linter - -## Lint Results -- - -## Commit Message Draft -- \ No newline at end of file From 355676a2653a3c4d030c13b3b3c3ac04cf24af9b Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 20 Jun 2026 14:36:35 +0200 Subject: [PATCH 5/8] Fixed everything but the (id,ref) encoding --- InteractiveHtmlBom/web/ibom.css | 23 ++++++++- InteractiveHtmlBom/web/ibom.js | 90 ++++++++++++++++++++++----------- 2 files changed, 81 insertions(+), 32 deletions(-) diff --git a/InteractiveHtmlBom/web/ibom.css b/InteractiveHtmlBom/web/ibom.css index 823f52f..587fec2 100644 --- a/InteractiveHtmlBom/web/ibom.css +++ b/InteractiveHtmlBom/web/ibom.css @@ -888,13 +888,32 @@ a { } .copy-link-button { - font-size: 12px; + font-size: 1em; border: none; background: transparent; + background-color: transparent !important; cursor: pointer; vertical-align: middle; } .copy-link-button:hover { - opacity: 0.7; + opacity: 0.3; +} + +.copy-status { + display: inline-block; + margin-left: 5px; + padding: 2px 6px; + border: 1px solid #ccc; + border-radius: 3px; + font-size: 12px; + + opacity: 0; + visibility: hidden; + transition: opacity 0.4s ease; +} + +.copy-status.visible { + opacity: 1; + visibility: visible; } \ No newline at end of file diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index 4e5156b..9a53a12 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -674,19 +674,7 @@ function populateBomBody(placeholderColumn = null, placeHolderElements = null) { // Add copy button for net names in netlist mode if (settings.bommode === "netlist") { - var copyButton = document.createElement("button"); - copyButton.className = "copy-link-button"; - copyButton.title = "Copy deep-link URL"; - copyButton.innerHTML = "🔗"; - copyButton.style.cssText = "margin-left: 5px; font-size: 10pt; border: none; background: transparent; cursor: pointer; height: 100%"; - (function(currentNetname) { - copyButton.onclick = function(e) { - e.stopPropagation(); - var url = new URL(window.location.href); - url.searchParams.set("net", "\"" + currentNetname + "\""); - copyToClipboard(url.toString()); - }; - })(netname); + var copyButton = createCopyButton("net", netname); td.appendChild(copyButton); } @@ -745,23 +733,8 @@ function populateBomBody(placeholderColumn = null, placeHolderElements = null) { // Add copy button for component references in ungrouped mode if (settings.bommode === "ungrouped") { - var copyButton = document.createElement("button"); - copyButton.className = "copy-link-button"; - copyButton.title = "Copy deep-link URL"; - copyButton.innerHTML = "🔗"; - copyButton.style.cssText = "margin-left: 5px; font-size: 10pt; border: none; background: transparent; cursor: pointer; height: 100%"; - var refName = references[0][0]; - (function(currentRefname) { - copyButton.onclick = function(e) { - e.stopPropagation(); - // Get the first reference to create URL (since we have multiple refs, we'll use the first one) - var url = new URL(window.location.href); - url.searchParams.set("ref", "\"" + currentRefname + "\""); - copyToClipboard(url.toString()); - - }; - })(refName); - td.appendChild(copyButton); + var copyButton = createCopyButton("ref", references[0][0]); + td.appendChild(copyButton); } @@ -826,6 +799,63 @@ function populateBomBody(placeholderColumn = null, placeHolderElements = null) { }); } +function createCopyButton(type, value) { + var copyButton = document.createElement("button"); + copyButton.className = "copy-link-button"; + copyButton.title = "Copy deep-link URL"; + copyButton.innerHTML = "🔗"; + + // status box for visual feedback + var statusBox = document.createElement("span"); + statusBox.className = "copy-status"; + statusBox.textContent = "Copied!"; + + function buildUrl() { + var url = new URL(window.location.href); + + if (type === "net") { + url.searchParams.set("net", value); + } else if (type === "ref") { + url.searchParams.set("ref", value); + } + + return url.toString(); + } + + // Left-click -> copy + copyButton.addEventListener("click", function (e) { + e.stopPropagation(); + + var url = buildUrl(); + copyToClipboard(url); + + statusBox.classList.add("visible"); + + clearTimeout(statusBox.hideTimer); + + statusBox.hideTimer = setTimeout(function () { + statusBox.classList.remove("visible"); + }, 2000); + }); + + // Right-click -> open in new window + copyButton.addEventListener("mousedown", function (e) { + if (e.button === 1) { + e.preventDefault(); + e.stopPropagation(); + + window.open(buildUrl(), "_blank"); + } + }); + + // return with a wrapper + var wrapper = document.createElement("span"); + wrapper.appendChild(copyButton); + wrapper.appendChild(statusBox); + + return wrapper; +} + function copyToClipboard(text) { var textArea = document.createElement("textarea"); textArea.className = "clipboard-temp"; From f867ce8d80a2025527d7024f015913fd2f6fb60a Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 20 Jun 2026 14:47:53 +0200 Subject: [PATCH 6/8] copy link button height fix --- InteractiveHtmlBom/web/ibom.css | 1 + 1 file changed, 1 insertion(+) diff --git a/InteractiveHtmlBom/web/ibom.css b/InteractiveHtmlBom/web/ibom.css index 587fec2..aed245c 100644 --- a/InteractiveHtmlBom/web/ibom.css +++ b/InteractiveHtmlBom/web/ibom.css @@ -890,6 +890,7 @@ a { .copy-link-button { font-size: 1em; border: none; + height: 1.5em; background: transparent; background-color: transparent !important; cursor: pointer; From 77e3cadd217bf824427aafe0619f3ab6eb8dda14 Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 20 Jun 2026 16:18:13 +0200 Subject: [PATCH 7/8] reference and ID used for linking. Error handling logic still needed --- InteractiveHtmlBom/web/ibom.js | 52 ++++++++++++++++++++++++++++++++-- 1 file changed, 50 insertions(+), 2 deletions(-) diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index 9a53a12..ed3c444 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -816,7 +816,22 @@ function createCopyButton(type, value) { if (type === "net") { url.searchParams.set("net", value); } else if (type === "ref") { + // For reference links, also include the ID to make it more robust url.searchParams.set("ref", value); + + // Try to find the corresponding ID for this reference + var id = null; + if (pcbdata && pcbdata.footprints) { + for (var i = 0; i < pcbdata.footprints.length; i++) { + if (pcbdata.footprints[i].ref === value) { + id = i; + break; + } + } + } + if (id !== null) { + url.searchParams.set("id", id); + } } return url.toString(); @@ -872,6 +887,14 @@ function copyToClipboard(text) { } } catch (err) { console.error('Could not copy text: ', err); + // Fallback to navigator.clipboard if execCommand fails + try { + navigator.clipboard.writeText(text).catch(function(err) { + console.error('Could not copy text with clipboard API: ', err); + }); + } catch (clipboardErr) { + console.error('Clipboard API also failed: ', clipboardErr); + } } document.body.removeChild(textArea); } @@ -1328,6 +1351,16 @@ function selectComponentByReference(ref) { // If component not found, do nothing (preserve existing behavior) } +function validateReferenceForId(ref, id) { + // Validate that the reference corresponds to the given ID in pcbdata + if (!pcbdata || !pcbdata.footprints || id >= pcbdata.footprints.length) { + return false; + } + + // Check if the footprint at the specified ID has the correct reference + return pcbdata.footprints[id].ref === ref; +} + function constrain(number, min, max) { return Math.min(Math.max(parseInt(number), min), max); } @@ -1457,13 +1490,28 @@ window.onload = function (e) { // Parse URL parameters for deep-linking var urlParams = new URLSearchParams(window.location.search); var refParam = urlParams.get('ref') || urlParams.get('component'); + var idParam = urlParams.get('id'); + if (refParam) { // Change layout to ungrouped changeBomMode('ungrouped'); // Extract the value from the "" or the '' string refParam = refParam.replace(/^["']|["']$/g, ""); - // Try to find and select the component - selectComponentByReference(refParam); + + // If we have both ref and id parameters, validate them together + if (idParam !== null) { + var id = parseInt(idParam); + if (!isNaN(id) && validateReferenceForId(refParam, id)) { + // Both parameters are valid, select the component + selectComponentByReference(refParam); + } else { + // Only ref parameter is valid, select by reference + selectComponentByReference(refParam); + } + } else { + // Only ref parameter is provided, select by reference + selectComponentByReference(refParam); + } } // Handle net parameter for deep-linking to nets From 5aa5f9bec683ae072f3318aebcce7665236fe1e8 Mon Sep 17 00:00:00 2001 From: dani007200964 Date: Sat, 20 Jun 2026 20:57:22 +0200 Subject: [PATCH 8/8] Ugly, but working prototype for warning window --- InteractiveHtmlBom/web/ibom.css | 158 +++++++++++++++++++++++++ InteractiveHtmlBom/web/ibom.js | 201 +++++++++++++++++++++++--------- 2 files changed, 302 insertions(+), 57 deletions(-) diff --git a/InteractiveHtmlBom/web/ibom.css b/InteractiveHtmlBom/web/ibom.css index aed245c..7092dac 100644 --- a/InteractiveHtmlBom/web/ibom.css +++ b/InteractiveHtmlBom/web/ibom.css @@ -19,6 +19,15 @@ --track-color-highlight: #D04040; --zone-color: #def5f1; --zone-color-highlight: #d0404080; + + --toast-bg: rgba(215,215,215,0.2); + --toast-border: #ffb629; + --toast-text: #222; + --toast-muted: #666; + --toast-header-border: rgba(0,0,0,0.12); + + --toast-primary: #42c642; + --toast-primary-hover: #30a130; } html, @@ -35,6 +44,11 @@ body { --pin1-outline-color-highlight: #ccff00; --track-color: #42524f; --zone-color: #42524f; + --toast-bg: rgba(215,215,215,0.20); + --toast-border: #ffb629; + --toast-text: #f3f4f6; + --toast-muted: #ffb629; + --toast-header-border: rgba(255,255,255,0.17); background-color: #252c30; color: #eee; } @@ -917,4 +931,148 @@ a { .copy-status.visible { opacity: 1; visibility: visible; +} + +.reference-warning-toast { + position: fixed; + top: 16px; + right: 16px; + + width: 420px; + max-width: calc(100vw - 32px); + + border: 2px solid var(--toast-border); + border-left: 4px var(--toast-border); + + border-radius: 12px; + + box-shadow: + 0 10px 25px rgba(0, 0, 0, 0.12), + 0 2px 8px rgba(0, 0, 0, 0.06); + + z-index: 10000; + + overflow: hidden; + + animation: toast-slide-in 0.25s ease-out; + + backdrop-filter: blur(10px); + background: var(--toast-bg); +} + +.toast-header { + display: flex; + align-items: center; + gap: 10px; + + padding: 14px 16px; + + border-bottom: 2px solid var(--toast-header-border); +} + +.toast-icon { + font-size: 18px; +} + +.toast-title { + flex: 1; + font-weight: 600; + font-size: 15px; + color: var(--toast-border); +} + +.toast-close { + border: none; + background: transparent; + cursor: pointer; + + color: #f3f4f6; + font-size: 22px; + line-height: 1; + + padding: 0; +} + +.toast-close:hover { + color: #ffb629; +} + +.toast-body { + padding: 16px; + color: var(--toast-text); + line-height: 1.5; +} + +.toast-body p { + margin: 0; +} + +.toast-body p + p { + margin-top: 8px; +} + +.toast-note { + color: var(--toast-muted); + font-size: 14px; +} + +.toast-actions { + display: flex; + justify-content: flex-end; + gap: 10px; + + padding: 0 16px 16px; +} + +.btn { + border: none; + border-radius: 8px; + + padding: 10px 16px; + + font-size: 14px; + font-weight: 500; + + cursor: pointer; + + width: auto; + height: auto; + + transition: + background-color 0.15s, + transform 0.1s; +} + +.btn:hover { + transform: translateY(-1px); +} + +.btn-primary { + background: #42c642; + color: white; +} + +.btn-primary:hover { + background: #30A130; +} + +.btn-secondary { + background: #f3f4f6; + color: #111827; +} + +.btn-secondary:hover { + background: #e5e7eb; +} + +@keyframes toast-slide-in { + from { + opacity: 0; + transform: translateX(24px); + } + + to { + opacity: 1; + transform: translateX(0); + } } \ No newline at end of file diff --git a/InteractiveHtmlBom/web/ibom.js b/InteractiveHtmlBom/web/ibom.js index ed3c444..79dc1f4 100644 --- a/InteractiveHtmlBom/web/ibom.js +++ b/InteractiveHtmlBom/web/ibom.js @@ -810,6 +810,9 @@ function createCopyButton(type, value) { statusBox.className = "copy-status"; statusBox.textContent = "Copied!"; + // Cache footprint references for faster lookups (only build if needed) + var footprintRefCache = null; + function buildUrl() { var url = new URL(window.location.href); @@ -822,12 +825,18 @@ function createCopyButton(type, value) { // Try to find the corresponding ID for this reference var id = null; if (pcbdata && pcbdata.footprints) { - for (var i = 0; i < pcbdata.footprints.length; i++) { - if (pcbdata.footprints[i].ref === value) { - id = i; - break; + // Build cache if needed + if (!footprintRefCache) { + footprintRefCache = {}; + for (var i = 0; i < pcbdata.footprints.length; i++) { + footprintRefCache[pcbdata.footprints[i].ref] = i; } } + + // Use the cache to get ID quickly + if (footprintRefCache[value] !== undefined) { + id = footprintRefCache[value]; + } } if (id !== null) { url.searchParams.set("id", id); @@ -871,6 +880,120 @@ function createCopyButton(type, value) { return wrapper; } +function validateReferenceForId(ref, id) { + // Validate that the reference corresponds to the given ID in pcbdata + if (!pcbdata || !pcbdata.footprints || id >= pcbdata.footprints.length) { + return false; + } + + // Check if the footprint at the specified ID has the correct reference + return pcbdata.footprints[id].ref === ref; +} + +function showReferenceMismatchWarning(ref, id) { + // Ha már van ilyen figyelmeztetés, töröljük + document + .querySelectorAll(".reference-warning-toast") + .forEach(el => el.remove()); + + const toast = document.createElement("div"); + toast.className = "reference-warning-toast"; + + toast.innerHTML = ` +
+ ⚠️ + Reference mismatch + +
+ +
+

+ Reference ${escapeHtml(ref)} does not match the + expected reference for ID ${id}. +

+ +

+ This link may be stale. Choose which value to use. +

+
+ +
+ + + +
+ `; + + toast.querySelector(".toast-close").addEventListener("click", () => { + toast.remove(); + }); + + toast.querySelector(".btn-primary").addEventListener("click", () => { + toast.remove(); + selectComponentByReference(ref); + }); + + toast.querySelector(".btn-secondary").addEventListener("click", () => { + toast.remove(); + selectComponentById(id); + }); + + document.body.appendChild(toast); +} + +function escapeHtml(str) { + const div = document.createElement("div"); + div.textContent = str; + return div.innerHTML; +} + +function selectComponentByReference(ref) { + // Find the footprint with matching reference + var footprintIndex = -1; + if (pcbdata && pcbdata.footprints) { + for (var i = 0; i < pcbdata.footprints.length; i++) { + if (pcbdata.footprints[i].ref === ref) { + footprintIndex = i; + break; + } + } + } + + // If we found the component, select it + if (footprintIndex !== -1) { + // Use the existing footprintIndexToHandler to trigger selection + if (footprintIndex in footprintIndexToHandler) { + footprintIndexToHandler[footprintIndex](); + // Scroll to the selected row to center it on screen + if (currentHighlightedRowId) { + smoothScrollToRow(currentHighlightedRowId); + } + } else { + // If no handler exists, try to find the row manually + for (var i = 0; i < highlightHandlers.length; i++) { + var handlerInfo = highlightHandlers[i]; + if (handlerInfo.handler && handlerInfo.handler.refs) { + // Check if any of the references in this row match our target ref + for (var j = 0; j < handlerInfo.handler.refs.length; j++) { + if (handlerInfo.handler.refs[j][0] === ref) { + handlerInfo.handler(); + if (currentHighlightedRowId) { + smoothScrollToRow(currentHighlightedRowId); + } + break; + } + } + } + } + } + } + // If component not found, do nothing (preserve existing behavior) +} + function copyToClipboard(text) { var textArea = document.createElement("textarea"); textArea.className = "clipboard-temp"; @@ -1310,55 +1433,12 @@ function updateCheckboxStats(checkbox) { td.lastChild.innerHTML = checked + "/" + total + " (" + Math.round(percent) + "%)"; } -function selectComponentByReference(ref) { - // Find the footprint with matching reference - var footprintIndex = -1; - for (var i = 0; i < pcbdata.footprints.length; i++) { - if (pcbdata.footprints[i].ref === ref) { - footprintIndex = i; - break; - } +function selectComponentById(id) { + // Find the footprint with matching ID + if (pcbdata && pcbdata.footprints && id < pcbdata.footprints.length) { + var ref = pcbdata.footprints[id].ref; + selectComponentByReference(ref); } - - // If we found the component, select it - if (footprintIndex !== -1) { - // Use the existing footprintIndexToHandler to trigger selection - if (footprintIndex in footprintIndexToHandler) { - footprintIndexToHandler[footprintIndex](); - // Scroll to the selected row to center it on screen - if (currentHighlightedRowId) { - smoothScrollToRow(currentHighlightedRowId); - } - } else { - // If no handler exists, try to find the row manually - for (var i = 0; i < highlightHandlers.length; i++) { - var handlerInfo = highlightHandlers[i]; - if (handlerInfo.handler && handlerInfo.handler.refs) { - // Check if any of the references in this row match our target ref - for (var j = 0; j < handlerInfo.handler.refs.length; j++) { - if (handlerInfo.handler.refs[j][0] === ref) { - handlerInfo.handler(); - if (currentHighlightedRowId) { - smoothScrollToRow(currentHighlightedRowId); - } - break; - } - } - } - } - } - } - // If component not found, do nothing (preserve existing behavior) -} - -function validateReferenceForId(ref, id) { - // Validate that the reference corresponds to the given ID in pcbdata - if (!pcbdata || !pcbdata.footprints || id >= pcbdata.footprints.length) { - return false; - } - - // Check if the footprint at the specified ID has the correct reference - return pcbdata.footprints[id].ref === ref; } function constrain(number, min, max) { @@ -1497,15 +1577,22 @@ window.onload = function (e) { changeBomMode('ungrouped'); // Extract the value from the "" or the '' string refParam = refParam.replace(/^["']|["']$/g, ""); - + // If we have both ref and id parameters, validate them together if (idParam !== null) { var id = parseInt(idParam); - if (!isNaN(id) && validateReferenceForId(refParam, id)) { - // Both parameters are valid, select the component - selectComponentByReference(refParam); + if (!isNaN(id)) { + if (validateReferenceForId(refParam, id)) { + // Both parameters are valid, select the component + selectComponentByReference(refParam); + } else { + // Parameters don't match, show warning + showReferenceMismatchWarning(refParam, id); + // Fallback to selecting by reference + selectComponentByReference(refParam); + } } else { - // Only ref parameter is valid, select by reference + // Invalid ID, fallback to selecting by reference only selectComponentByReference(refParam); } } else {