130 lines
7.4 KiB
Markdown
130 lines
7.4 KiB
Markdown
# Submitting components as Altium 365 Part Requests (web browser)
|
|
|
|
When the central library is a managed **Altium 365 Workspace** and the operator is **not an
|
|
admin**, the skill's end task can be to submit each finished component as a **Part Request**
|
|
through the Workspace's web UI, driven by browser automation (Claude-in-Chrome). A librarian
|
|
then approves each request into the managed library. This runs in the operator's **own Chrome,
|
|
using their existing Altium 365 login**, so it needs **no API token and no admin rights** — it
|
|
just does what the engineer would do by hand, for every component in the run.
|
|
|
|
This is the browser alternative to the headless API push (`altium365_push.py`, if a token is
|
|
ever available) and to the Gitea push. Use whichever matches how the org consumes the library.
|
|
|
|
## Prerequisites (each run)
|
|
|
|
- **Chrome open** with the Claude-in-Chrome extension enabled, and **site permission granted**
|
|
for the Workspace domain (e.g. `vecmocon.altium365.com`).
|
|
- **Signed in** to the Altium 365 Workspace as any member with rights to create Part Requests.
|
|
- **The component files on the LOCAL machine** — the browser uploads attachments from local
|
|
disk, so each component's `.SchLib` (with parameters written), `.PcbLib`, and datasheet must
|
|
exist on the operator's computer. If the skill produced them in the cloud, commit them to the
|
|
device first (device bridge) into a known folder, and put those local paths in the manifest.
|
|
- **The manifest** of components to submit this run (below).
|
|
- **Decisions the operator confirms once**: the default **Assign to** (the librarian/group), the
|
|
**Component Type** mapping for each typeid, and an optional **Required By** date.
|
|
|
|
## Per-component field mapping (the Part Request form)
|
|
|
|
| Form field | Value (from the skill's per-part data) |
|
|
|---|---|
|
|
| Manufacturer | `Manufacturer` param (e.g. `Taiyo Yuden`) |
|
|
| Manufacturer Part Numbers | `Manufacturer Part` param (the MPN) |
|
|
| Description | `Description` param (SOP format, e.g. `CHIP_CAP_1uF_6.3v_±10%_0402_x5r`) |
|
|
| Component Type | the typeid mapped to the Workspace's matching component type (confirm once per typeid) |
|
|
| State | leave `Opened: New` |
|
|
| Required By Date | optional org default |
|
|
| Assign to | the configured librarian / group |
|
|
| Parameters → Add | every parameter from the full set (name + value) |
|
|
| Attachments | the `.SchLib`, `.PcbLib`, and datasheet files |
|
|
| Parts List → Add | optional: add the MPN as a part choice so the librarian's mapping is pre-seeded |
|
|
|
|
## The manifest
|
|
|
|
The skill writes one `part_requests.json` per run listing every component it processed, so the
|
|
browser step can loop without re-deriving anything:
|
|
|
|
```json
|
|
{"requests":[
|
|
{"manufacturer":"Taiyo Yuden","mpn":"JMK105BJ105KV-F",
|
|
"description":"CHIP_CAP_1uF_6.3v_±10%_0402_x5r","component_type":"Capacitor",
|
|
"parameters":{"Value":"1u","Voltage(V)":"6.3","Tolerance":"±10%","...":"..."},
|
|
"files":["C:\\...\\JMK105BJ105KV-F.SchLib","C:\\...\\<footprint>.PcbLib","C:\\...\\<mpn>.pdf"],
|
|
"assignee":"<librarian>","required_by":""}
|
|
]}
|
|
```
|
|
|
|
Build it from each component's `params.json` plus the local file paths (after committing files
|
|
to the device).
|
|
|
|
## Browser procedure (looped per component)
|
|
|
|
Start the browser session with `tabs_context_mcp`, then for each entry in the manifest:
|
|
|
|
1. Navigate to **Library → Part Requests → new request**.
|
|
2. Fill **Manufacturer**, **Manufacturer Part Numbers**, **Description**.
|
|
3. Choose **Component Type**; set **Assign to**; optional **Required By Date**. Leave State as
|
|
`Opened: New`.
|
|
4. **Parameters → Add**: add each parameter name + value.
|
|
5. **Attachments** (Choose file / drop): upload the `.SchLib`, `.PcbLib`, and datasheet.
|
|
6. Review, then **Save**. Record the auto-assigned **Request Id**.
|
|
7. Move to the next entry.
|
|
|
|
## Standalone Selenium path (token-free at scale) — `scripts/altium365_part_request.py`
|
|
|
|
Live browser-driving costs Claude tokens per component. For a whole library, use the Selenium
|
|
script instead: it's authored once, then runs on the operator's machine over any number of
|
|
components with **zero Claude tokens per part**. It attaches to the operator's already-signed-in
|
|
Chrome (remote-debugging port), so it reuses the Altium 365 session — no credentials handled.
|
|
|
|
Captured selectors (live form at `<workspace>/partrequestsmanagement/Tasks/Add`; Altium "afs"
|
|
design system + Selectize.js dropdowns):
|
|
|
|
- Manufacturer → `input#Manufacturer`
|
|
- Manufacturer Part Numbers → `textarea#ManufacturerPartNumbers`
|
|
- Description → `textarea#Description`
|
|
- Component Type / Assign to → Selectize: click the `.selectize-input` after the label, then the
|
|
`.selectize-dropdown-content .option` whose text matches.
|
|
- Parameters → afs-table under the "Parameters" label; each "Add" (`a.afs-link`) click adds a
|
|
`div.afs-table__tr` with two `input.afs-input__control` (name, value).
|
|
- Attachments → `input#fileupload` (Selenium `send_keys` the local file path(s)).
|
|
- Save → `button.afs-btn_primary` (text "Save").
|
|
|
|
Component Type options (must match one exactly): Test Points, Clock&Timing, Memory, Wireless,
|
|
Transformers, Mechanicals, Capacitors, Transistors, Drivers, Optoelectronics, Power Supply,
|
|
Audio, Fuses, Switches, Integrated Circuits, Logic, Diodes, Interface, Miscellaneous, Radio&RF,
|
|
Sensors, Processors, Mechanical, Inductors, LED, Amplifiers, Resistors, Data Converters, Relays,
|
|
Batteries, Connectors, Crystals & Oscillators. (Map each typeid to one of these when building the
|
|
manifest — e.g. `CER → Capacitors`.)
|
|
|
|
Run it:
|
|
```bash
|
|
# 1) close Chrome, relaunch on the operator's own profile with a debug port:
|
|
# chrome.exe --remote-debugging-port=9222 --user-data-dir="%LOCALAPPDATA%\Google\Chrome\User Data"
|
|
# 2) sign into the Workspace in that Chrome, then:
|
|
python scripts/altium365_part_request.py --manifest part_requests.json \
|
|
--base https://<workspace>.365.altium.com [--review-first | --no-submit]
|
|
```
|
|
Default operation is **review mode**: the runner (`local_runner.py`) invokes the submitter with
|
|
`--no-submit`, so it fills the form completely — fields, parameters, and all attachments — and
|
|
**leaves it on screen for the operator to review and click Save**. This is the review-first gate
|
|
and works even unattended (a console "press Enter" can't). Set `"auto_submit": true` in
|
|
`runner_config.json` only to submit without review. (`--review-first` is a console-only variant
|
|
that pauses for Enter.)
|
|
|
|
Build the manifest with `scripts/build_part_request_manifest.py` (it maps the typeid to the
|
|
Workspace Component Type and pulls manufacturer/MPN/Description/parameters from the schlib
|
|
`params.json`). The skill writes `part_requests.json` and commits it + each component's files to
|
|
the operator's inbox (device bridge) so the local `files` paths resolve.
|
|
|
|
## Safety and auditing
|
|
|
|
- On the **first component of a run**, fill everything and **stop at Save** for the operator to
|
|
eyeball the mapping. Once they confirm it looks right, Save it and loop the rest unattended.
|
|
- **Log every submitted Request Id** (and any component that failed) so the run is auditable and
|
|
re-runnable — never silently skip a component.
|
|
- Browser automation follows the live UI. If a field, dropdown option, or a popup doesn't match
|
|
what's expected, **pause and ask** rather than guessing — a wrong Component Type or a
|
|
half-filled request is worse than one clarifying question.
|
|
- Don't trigger native file-dialog blocking: use the extension's file-upload path for
|
|
attachments, not an OS dialog.
|