Restyle staff and console UIs; add UI-Docs walkthrough and review PDF.
Some checks are pending
offline / test (push) Waiting to run
Match CS/sales/accounting/access-staff to the portal indigo system with dollar amounts, skip links, and empty states. Fleet replica actions move into overflow menus, roles become chips, Docs become cards, and the header copy reflects the 0.0.0.0 bind. Simulator uses the same shell (orange only for faults). Portal API keys are masked; admin customers edit in a drawer. Catalog uses system-ui. New UI-Docs repo holds screenshots, usage notes, and UI-REVIEW.pdf.
1
packages/ui-docs/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
||||
3
packages/ui-docs/NATS.md
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# NATS
|
||||
|
||||
UI-Docs is documentation only. It does not subscribe, publish, or request any `verae.*` subject.
|
||||
24
packages/ui-docs/README.md
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
# UI-Docs
|
||||
|
||||
Walkthrough screenshots, usage instructions, and a review PDF for every operator, staff, portal, admin, simulator, and catalog surface in the Verae Time × Zapier lab.
|
||||
|
||||
**Forgejo:** https://git.georgelambert.org/marchon/UI-Docs
|
||||
|
||||
## Open the review
|
||||
|
||||
- [UI-REVIEW.pdf](UI-REVIEW.pdf) — screenshots, how to use each screen, remaining issues
|
||||
- [WALKTHROUGH.md](WALKTHROUGH.md) — click-by-click
|
||||
- [REPORT.md](REPORT.md) — issues still to consider
|
||||
- [screenshots/](screenshots/) — PNG atlas
|
||||
|
||||
## Recapture
|
||||
|
||||
Lab processes must already be listening (`:3850` fleet, `:3847` simulator, `:3011` CS, `:3012` sales, `:3013` accounting, `:3025` staff, `:3000` edge).
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run walk # headless Chrome → screenshots/ + walkthrough-console.json
|
||||
npm run pdf # reportlab → UI-REVIEW.pdf
|
||||
```
|
||||
|
||||
Chrome path: `CHROME_PATH` or `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`.
|
||||
44
packages/ui-docs/REPORT.md
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
# UI issues still to consider
|
||||
|
||||
Second full walkthrough (2026-09-11): 32 screenshots, 0 application console errors on product UIs. Surfaces are visually consistent (indigo, 12px radius, dollars). Primary actions are obvious. Remaining work is listed here for human review. Full screenshot atlas and the same table: [UI-REVIEW.pdf](UI-REVIEW.pdf).
|
||||
|
||||
## Fixed in this pass
|
||||
|
||||
| Item | Result |
|
||||
|------|--------|
|
||||
| CS/sales/accounting/access-staff unstyled cents forms | Indigo shell, USD, agent/customer labels, empty illustrations |
|
||||
| Fleet pause/resume/restart/on/off/pause crowding | One ⋯ menu per replica and per service; Power is status |
|
||||
| Docs tab bullet dump | Cards matching Fleet |
|
||||
| Simulator cream/orange brand | Indigo; orange = fault inject only |
|
||||
| Header LOOPBACK vs 0.0.0.0 bind | `operator LAN · binds 0.0.0.0:3850` |
|
||||
| Add machine truncated roles field | Chips |
|
||||
| Admin customers inline-edit table | List + edit drawer |
|
||||
| Portal API key always visible | Masked + Reveal/Copy/Regenerate |
|
||||
| Catalog Georgia on indigo | system-ui |
|
||||
| Trace hop grid clipping names | Wrapping columns |
|
||||
| Empty “No invoices yet” | Illustrated empty state |
|
||||
| Fleet on/off looking like toggles | Status pills |
|
||||
| Department pages a11y | `lang`, skip link, focus-visible |
|
||||
| Nav hit area/contrast | 44px tabs, `#c7c9ff` on indigo |
|
||||
| Swagger as customer UI | Labeled stock |
|
||||
|
||||
## Still to consider
|
||||
|
||||
| Severity | Issue | Suggestion |
|
||||
|----------|-------|------------|
|
||||
| High | Staff review headings show `cust_1` because the ledger has no display name | Join statements to zappier-edge customer name, or a customer typeahead |
|
||||
| High | CS/sales/accounting HTML has no login (LAN trust) | Staff SSO or shared cookie before any non-lab bind |
|
||||
| Med | Catalog is still a bibliography | Card index like console Docs |
|
||||
| Med | Swagger remains stock | Keep for integrators; do not skin |
|
||||
| Med | Fleet add-machine identity path truncates | Two-row form + file picker |
|
||||
| Med | Intentionally disabled machines use degraded yellow | Neutral grey when disabled on purpose |
|
||||
| Low | Portal statement empty lists still wrap the illustration in a table row | Same card empty state as invoices |
|
||||
| Low | Fleet ⋯ can open off-screen at the bottom of a long table | Flip the menu upward |
|
||||
| Low | access-staff and CS HTML are twins | Share one template |
|
||||
| Low | Simulator empty console is a black void | Placeholder “Run a step…” |
|
||||
|
||||
## Visual revalidation
|
||||
|
||||
- **Appealing:** staff and console now match portal/admin; simulator no longer looks like a second product.
|
||||
- **Obvious:** Review account, Apply credit, Edit, Reveal/Copy, Run step, ⋯.
|
||||
- **Comprehensive:** review, credit, quote, export, fleet power, trace, docs, portal billing, admin customers — covered. Missing: staff identity join and catalog IA (above).
|
||||
5
packages/ui-docs/SUMMARY.md
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
# UI-Docs
|
||||
|
||||
Walkthrough screenshots, usage instructions, and a review PDF for every operator, staff, portal, admin, simulator, and catalog surface.
|
||||
|
||||
**Forgejo:** https://git.georgelambert.org/marchon/UI-Docs
|
||||
840
packages/ui-docs/UI-REVIEW.pdf
Normal file
127
packages/ui-docs/WALKTHROUGH.md
Normal file
|
|
@ -0,0 +1,127 @@
|
|||
# UI walkthrough (operator, staff, customers)
|
||||
|
||||
Captured 2026-09-11. Browser console: no application errors on the product UIs (favicon data-URI). Design tokens: `--accent #4f46e5`, `--bg #f4f5fb`, 12px radius, indigo header.
|
||||
|
||||
## 1. Operator console — Fleet
|
||||
|
||||
Open **http://127.0.0.1:3850/**.
|
||||
|
||||

|
||||
|
||||
1. Header kicker reads **operator LAN · binds 0.0.0.0:3850**. NATS stays private.
|
||||
2. **Add machine:** pick roles as chips (`tree-node`, `archive-worm`, …), then **Add machine**.
|
||||
3. Machine cards show role pills and enable/disable.
|
||||
4. Services: **Health** is operational/degraded. **Power** is a status (`on` / `paused` / `off`), not a toggle.
|
||||
5. Click **⋯** on a replica or on Power for pause / resume / restart / start / stop.
|
||||
|
||||

|
||||
|
||||
## 2. Trace
|
||||
|
||||
Click **Trace**.
|
||||
|
||||

|
||||
|
||||
1. Pick an action (default Create Timestamp and Wait).
|
||||
2. Orange **Faults** box is inject-only.
|
||||
3. **Run step**. Hops wrap; module names are not clipped.
|
||||
|
||||

|
||||
|
||||
## 3. Docs
|
||||
|
||||
Click **Docs**. Cards match Fleet. High-level first.
|
||||
|
||||

|
||||
|
||||
## 4. Standalone simulator
|
||||
|
||||
Open **http://127.0.0.1:3847/**. Same indigo shell. Orange only on **Inject faults**.
|
||||
|
||||

|
||||
|
||||
**Run step** or a scenario (Register, Batch Merkle, …).
|
||||
|
||||

|
||||
|
||||
## 5. Customer service
|
||||
|
||||
Open **http://127.0.0.1:3011/**.
|
||||
|
||||
1. Customer id → **Review account**. Prepaid is dollars.
|
||||
2. **Amount (USD)** → **Apply credit**. Table lists `$5.00`, reason, agent name, when.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
## 6. Sales
|
||||
|
||||
**http://127.0.0.1:3012/** — **Review account** or **Show quote** (named fields, not a JSON dump).
|
||||
|
||||

|
||||
|
||||
## 7. Accounting
|
||||
|
||||
**http://127.0.0.1:3013/** — review plus **QuickBooks IIF** / **CSV**.
|
||||
|
||||

|
||||
|
||||
## 8. Staff access plane
|
||||
|
||||
**http://127.0.0.1:3025/** — same review/credit UI after `verae.access.authz.check`.
|
||||
|
||||

|
||||
|
||||
## 9. Admin
|
||||
|
||||
**http://127.0.0.1:3000/admin/**
|
||||
|
||||
| Username | Password |
|
||||
|----------|----------|
|
||||
| `admin` | `admin-dev-key` |
|
||||
| `demo` | `$$$Adm1n###` |
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**Customers** is a read-only list. **Edit** opens a drawer (email, type, multiplier, billing).
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
Invoices empty state until you **Generate** a period.
|
||||
|
||||

|
||||
|
||||
## 10. Customer portal
|
||||
|
||||
**http://127.0.0.1:3000/portal/** — create an account or sign in.
|
||||
|
||||

|
||||
|
||||
Dashboard: API key is **masked**. **Reveal**, **Copy** (full key to clipboard), **Regenerate**.
|
||||
|
||||

|
||||
|
||||

|
||||
|
||||

|
||||
|
||||
**API & pricing** notes that `/docs` is stock Swagger.
|
||||
|
||||

|
||||
|
||||
## 11. Swagger (not a customer surface)
|
||||
|
||||
**http://127.0.0.1:3000/docs** — vendor Swagger UI for integrators.
|
||||
|
||||

|
||||
|
||||
## 12. Catalog
|
||||
|
||||
**https://zapier.georgelambert.org/** — system-ui on the indigo header (not Georgia).
|
||||
|
||||

|
||||
925
packages/ui-docs/package-lock.json
generated
Normal file
|
|
@ -0,0 +1,925 @@
|
|||
{
|
||||
"name": "ui-docs",
|
||||
"version": "0.1.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "ui-docs",
|
||||
"version": "0.1.0",
|
||||
"dependencies": {
|
||||
"puppeteer-core": "^24.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@puppeteer/browsers": {
|
||||
"version": "2.13.2",
|
||||
"resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.13.2.tgz",
|
||||
"integrity": "sha512-5EUZSUIc37H6aIXyWO0Z4y8NlF8NnjgmqeQgOGiswAU7pY0HOo16ho4+alIWmSfdZnjqBRawMsP3I5YqLSn6kw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"debug": "^4.4.3",
|
||||
"extract-zip": "^2.0.1",
|
||||
"progress": "^2.0.3",
|
||||
"proxy-agent": "^6.5.0",
|
||||
"semver": "^7.7.4",
|
||||
"tar-fs": "^3.1.1",
|
||||
"yargs": "^17.7.2"
|
||||
},
|
||||
"bin": {
|
||||
"browsers": "lib/cjs/main-cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@tootallnate/quickjs-emscripten": {
|
||||
"version": "0.23.0",
|
||||
"resolved": "https://registry.npmjs.org/@tootallnate/quickjs-emscripten/-/quickjs-emscripten-0.23.0.tgz",
|
||||
"integrity": "sha512-C5Mc6rdnsaJDjO3UpGW/CQTHtCKaYlScZTly4JIu97Jxo/odCiH0ITnDXSJPTOrEKk/ycSZ0AOgTmkDtkOsvIA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.20.2",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.20.2.tgz",
|
||||
"integrity": "sha512-xlvWf4Vs9n1PEVYwP1n4vvG07M6y8WgvJ2t0vbrWTmijsIHp1cS+uJ2kMIRdY3nHZK0nCYKrPeD171+SzF4/zw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~6.21.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/yauzl": {
|
||||
"version": "2.10.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.3.tgz",
|
||||
"integrity": "sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz",
|
||||
"integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-regex": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
|
||||
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/ast-types": {
|
||||
"version": "0.13.4",
|
||||
"resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.13.4.tgz",
|
||||
"integrity": "sha512-x1FCFnFifvYDDzTaLII71vG5uvDwgtmDTEVWAxrgeiR8VjMONcCXJx7E+USjDtHlwFmt9MysbqgF9b9Vjr6w+w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"tslib": "^2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/b4a": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/b4a/-/b4a-1.8.1.tgz",
|
||||
"integrity": "sha512-aiqre1Nr0B/6DgE2N5vwTc+2/oQZ4Wh1t4NznYY4E00y8LCt6NqdRv81so00oo27D8MVKTpUa/MwUUtBLXCoDw==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"react-native-b4a": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"react-native-b4a": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-events": {
|
||||
"version": "2.9.2",
|
||||
"resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.9.2.tgz",
|
||||
"integrity": "sha512-AIPKioV7/Y/8KfZ3AAhjPJxLLbY49S64Ym5DakZlUg75qQiTgUq9hEJoEwa4eUezPUlXRy/i5NpsKvo9jgKmoA==",
|
||||
"license": "Apache-2.0",
|
||||
"peerDependencies": {
|
||||
"bare-abort-controller": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-abort-controller": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-fs": {
|
||||
"version": "4.8.1",
|
||||
"resolved": "https://registry.npmjs.org/bare-fs/-/bare-fs-4.8.1.tgz",
|
||||
"integrity": "sha512-N1nnXdHZAOSstz0XiHikGS4HGMH4CnSwhqWdGQQMqqdvp4Jybm9sE3R1WVnpWVd4SFkc8ryPDBLViNLwiEqECg==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.5.4",
|
||||
"bare-path": "^3.0.0",
|
||||
"bare-stream": "^2.6.4",
|
||||
"bare-url": "^2.2.2",
|
||||
"fast-fifo": "^1.3.2"
|
||||
},
|
||||
"engines": {
|
||||
"bare": ">=1.28.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-buffer": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-path": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bare-path/-/bare-path-3.1.2.tgz",
|
||||
"integrity": "sha512-ZyKbsuuqK6Ag0K8pX6V5Txq6XeJRvY+wXucnFGRjiyVYP9YWDpIQugk/b+enRYrEYBJaqLzghRQpXPMR7341Nw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/bare-stream": {
|
||||
"version": "2.13.4",
|
||||
"resolved": "https://registry.npmjs.org/bare-stream/-/bare-stream-2.13.4.tgz",
|
||||
"integrity": "sha512-PcrQ8lVLbiJscNm1Kez+Yp4Gy4AHGcN1lzwjvf5NybWen7VvEgUfyfnXYJ2zNqWnzOfCb1Abq6lH8ti0syQszA==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.8.1",
|
||||
"streamx": "^2.25.0",
|
||||
"teex": "^1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bare-abort-controller": "*",
|
||||
"bare-buffer": "*",
|
||||
"bare-events": "*"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bare-abort-controller": {
|
||||
"optional": true
|
||||
},
|
||||
"bare-buffer": {
|
||||
"optional": true
|
||||
},
|
||||
"bare-events": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/bare-url": {
|
||||
"version": "2.5.4",
|
||||
"resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.5.4.tgz",
|
||||
"integrity": "sha512-Gxa7UVWBr0/edU1b+TJhn/AZvMQUj9OGspvYsaTYQrAbZA4BOTZGL3LiZxvD+CeMlDH4juwD84+eTAp/bLYW5g==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/basic-ftp": {
|
||||
"version": "5.3.1",
|
||||
"resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.1.tgz",
|
||||
"integrity": "sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/buffer-crc32": {
|
||||
"version": "0.2.13",
|
||||
"resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
|
||||
"integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/chromium-bidi": {
|
||||
"version": "14.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-14.0.0.tgz",
|
||||
"integrity": "sha512-9gYlLtS6tStdRWzrtXaTMnqcM4dudNegMXJxkR0I/CXObHalYeYcAMPrL19eroNZHtJ8DQmu1E+ZNOYu/IXMXw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"mitt": "^3.0.1",
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"devtools-protocol": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/cliui": {
|
||||
"version": "8.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
|
||||
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"string-width": "^4.2.0",
|
||||
"strip-ansi": "^6.0.1",
|
||||
"wrap-ansi": "^7.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "~1.1.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=7.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/data-uri-to-buffer": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-6.0.2.tgz",
|
||||
"integrity": "sha512-7hvf7/GW8e86rW0ptuwS3OcBGDjIi6SZva7hCyWC0yYry2cOPmLIjXAUHI6DK2HsnwJd9ifmt57i8eV2n4YNpw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.4.3",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
|
||||
"integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"supports-color": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/degenerator": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/degenerator/-/degenerator-5.0.1.tgz",
|
||||
"integrity": "sha512-TllpMR/t0M5sqCXfj85i4XaAzxmS5tVA16dqvdkMwGmzI+dXLXnw3J+3Vdv7VKw+ThlTMboK6i9rnZ6Nntj5CQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ast-types": "^0.13.4",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/devtools-protocol": {
|
||||
"version": "0.0.1608973",
|
||||
"resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1608973.tgz",
|
||||
"integrity": "sha512-Tpm17fxYzt+J7VrGdc1k8YdRqS3YV7se/M6KeemEqvUbq/n7At1rWVuXMxQgpWkdwSdIEKYbU//Bve+Shm4YNQ==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.5",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz",
|
||||
"integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.2.0",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
|
||||
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/escodegen": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz",
|
||||
"integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"esprima": "^4.0.1",
|
||||
"estraverse": "^5.2.0",
|
||||
"esutils": "^2.0.2"
|
||||
},
|
||||
"bin": {
|
||||
"escodegen": "bin/escodegen.js",
|
||||
"esgenerate": "bin/esgenerate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"source-map": "~0.6.1"
|
||||
}
|
||||
},
|
||||
"node_modules/esprima": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
|
||||
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
|
||||
"license": "BSD-2-Clause",
|
||||
"bin": {
|
||||
"esparse": "bin/esparse.js",
|
||||
"esvalidate": "bin/esvalidate.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/estraverse": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz",
|
||||
"integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esutils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
|
||||
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
|
||||
"license": "BSD-2-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/events-universal": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/events-universal/-/events-universal-1.0.1.tgz",
|
||||
"integrity": "sha512-LUd5euvbMLpwOF8m6ivPCbhQeSiYVNb8Vs0fQ8QjXo0JTkEHpz8pxdQf0gStltaPpw0Cca8b39KxvK9cfKRiAw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"bare-events": "^2.7.0"
|
||||
}
|
||||
},
|
||||
"node_modules/extract-zip": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz",
|
||||
"integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"debug": "^4.1.1",
|
||||
"get-stream": "^5.1.0",
|
||||
"yauzl": "^2.10.0"
|
||||
},
|
||||
"bin": {
|
||||
"extract-zip": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.17.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@types/yauzl": "^2.9.1"
|
||||
}
|
||||
},
|
||||
"node_modules/fast-fifo": {
|
||||
"version": "1.3.2",
|
||||
"resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
|
||||
"integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fd-slicer": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz",
|
||||
"integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pend": "~1.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/get-caller-file": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": "6.* || 8.* || >= 10.*"
|
||||
}
|
||||
},
|
||||
"node_modules/get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/get-uri": {
|
||||
"version": "6.0.5",
|
||||
"resolved": "https://registry.npmjs.org/get-uri/-/get-uri-6.0.5.tgz",
|
||||
"integrity": "sha512-b1O07XYq8eRuVzBNgJLstU6FYc1tS6wnMtF1I1D9lE8LxZSOGZ7LhxN54yPP6mGw5f2CkXY2BQUL9Fx41qvcIg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"basic-ftp": "^5.0.2",
|
||||
"data-uri-to-buffer": "^6.0.2",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/http-proxy-agent": {
|
||||
"version": "7.0.2",
|
||||
"resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
|
||||
"integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.0",
|
||||
"debug": "^4.3.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "7.0.6",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz",
|
||||
"integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/ip-address": {
|
||||
"version": "10.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.0.tgz",
|
||||
"integrity": "sha512-BGFsyJd5mpXp3rK6jIdADLNgpJUK1jnjzvYF8lK+VyDab9JAmqN0YOKDdP17HlgKb2+ehPgDc8EtnRLbGCAMhA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 12"
|
||||
}
|
||||
},
|
||||
"node_modules/is-fullwidth-code-point": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
|
||||
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "7.18.3",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz",
|
||||
"integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/mitt": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
||||
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/netmask": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/netmask/-/netmask-2.1.1.tgz",
|
||||
"integrity": "sha512-eonl3sLUha+S1GzTPxychyhnUzKyeQkZ7jLjKrBagJgPla13F+uQ71HgpFefyHgqrjEbCPkDArxYsjY8/+gLKA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"node_modules/pac-proxy-agent": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pac-proxy-agent/-/pac-proxy-agent-7.2.0.tgz",
|
||||
"integrity": "sha512-TEB8ESquiLMc0lV8vcd5Ql/JAKAoyzHFXaStwjkzpOpC5Yv+pIzLfHvjTSdf3vpa2bMiUQrg9i6276yn8666aA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@tootallnate/quickjs-emscripten": "^0.23.0",
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
"get-uri": "^6.0.1",
|
||||
"http-proxy-agent": "^7.0.0",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"pac-resolver": "^7.0.1",
|
||||
"socks-proxy-agent": "^8.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/pac-resolver": {
|
||||
"version": "7.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pac-resolver/-/pac-resolver-7.0.1.tgz",
|
||||
"integrity": "sha512-5NPgf87AT2STgwa2ntRMr45jTKrYBGkVU36yT0ig/n/GMAa3oPqhZfIQ2kMEimReg0+t9kZViDVZ83qfVUlckg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"degenerator": "^5.0.0",
|
||||
"netmask": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/pend": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz",
|
||||
"integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-agent": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-agent/-/proxy-agent-6.5.0.tgz",
|
||||
"integrity": "sha512-TmatMXdr2KlRiA2CyDu8GqR8EjahTG3aY3nXjdzFyoZbmB8hrBsTyMezhULIXKnC0jpfjlmiZ3+EaCzoInSu/A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
"http-proxy-agent": "^7.0.1",
|
||||
"https-proxy-agent": "^7.0.6",
|
||||
"lru-cache": "^7.14.1",
|
||||
"pac-proxy-agent": "^7.1.0",
|
||||
"proxy-from-env": "^1.1.0",
|
||||
"socks-proxy-agent": "^8.0.5"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz",
|
||||
"integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/puppeteer-core": {
|
||||
"version": "24.43.1",
|
||||
"resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.43.1.tgz",
|
||||
"integrity": "sha512-T5ScUMAsmhdNbgDR41AGESYeS6V9MSgetkSnVhhW+gXvzC42VesKCn5ld87gAZDJ6vLHL9GkRvY9WtQWSnwFbw==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"@puppeteer/browsers": "2.13.2",
|
||||
"chromium-bidi": "14.0.0",
|
||||
"debug": "^4.4.3",
|
||||
"devtools-protocol": "0.0.1608973",
|
||||
"typed-query-selector": "^2.12.2",
|
||||
"webdriver-bidi-protocol": "0.4.1",
|
||||
"ws": "^8.20.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/require-directory": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/semver": {
|
||||
"version": "7.8.5",
|
||||
"resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz",
|
||||
"integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==",
|
||||
"license": "ISC",
|
||||
"bin": {
|
||||
"semver": "bin/semver.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/smart-buffer": {
|
||||
"version": "4.2.0",
|
||||
"resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz",
|
||||
"integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 6.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.8.10",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz",
|
||||
"integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ip-address": "^10.1.1",
|
||||
"smart-buffer": "^4.2.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 10.0.0",
|
||||
"npm": ">= 3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/socks-proxy-agent": {
|
||||
"version": "8.0.5",
|
||||
"resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.5.tgz",
|
||||
"integrity": "sha512-HehCEsotFqbPW9sJ8WVYB6UbmIMv7kUUORIF2Nncq4VQvBfNBLibW9YZR5dlYCSUhwcD628pRllm7n+E+YTzJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"agent-base": "^7.1.2",
|
||||
"debug": "^4.3.4",
|
||||
"socks": "^2.8.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 14"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"license": "BSD-3-Clause",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/streamx": {
|
||||
"version": "2.28.1",
|
||||
"resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz",
|
||||
"integrity": "sha512-zEzXb0s5Cds7tqMH6rhZ05lcJydCWiQPEwiNngVqzsxCc962vLY4Uw+mW7od8kDH258k2Uz/JrOkdIAAhSh9VA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"events-universal": "^1.0.0",
|
||||
"fast-fifo": "^1.3.2",
|
||||
"text-decoder": "^1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/string-width": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"emoji-regex": "^8.0.0",
|
||||
"is-fullwidth-code-point": "^3.0.0",
|
||||
"strip-ansi": "^6.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/strip-ansi": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
|
||||
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-regex": "^5.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-fs": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.1.3.tgz",
|
||||
"integrity": "sha512-/hU4AXnIdZu+Gvl1pk0oI5f5HxWsCJRtY2aFaJdk9VvyL48DWU6iU5WAIPG+wIi1YvWA6eTJvIviP/tMAZZNwQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pump": "^3.0.0",
|
||||
"tar-stream": "^3.1.5"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"bare-fs": "^4.0.1",
|
||||
"bare-path": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.2.1.tgz",
|
||||
"integrity": "sha512-nqsEO8zLZJvrOMdEwkA0QdCLFbetHMn95Zqu4fKwX+hkaTWJPZZOrxx/PwtxoK0MMGQmBQNRW3CPs8IFYQz4cQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4",
|
||||
"bare-fs": "^4.5.5",
|
||||
"fast-fifo": "^1.2.0",
|
||||
"streamx": "^2.15.0"
|
||||
}
|
||||
},
|
||||
"node_modules/teex": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
|
||||
"integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"streamx": "^2.12.5"
|
||||
}
|
||||
},
|
||||
"node_modules/text-decoder": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.7.tgz",
|
||||
"integrity": "sha512-vlLytXkeP4xvEq2otHeJfSQIRyWxo/oZGEbXrtEEF9Hnmrdly59sUbzZ/QgyWuLYHctCHxFF4tRQZNQ9k60ExQ==",
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"b4a": "^1.6.4"
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/typed-query-selector": {
|
||||
"version": "2.12.2",
|
||||
"resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz",
|
||||
"integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/undici-types": {
|
||||
"version": "6.21.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
|
||||
"integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/webdriver-bidi-protocol": {
|
||||
"version": "0.4.1",
|
||||
"resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.1.tgz",
|
||||
"integrity": "sha512-ARrjNjtWRRs2w4Tk7nqrf2gBI0QXWuOmMCx2hU+1jUt6d00MjMxURrhxhGbrsoiZKJrhTSTzbIrc554iKI10qw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/wrap-ansi": {
|
||||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
|
||||
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^4.0.0",
|
||||
"string-width": "^4.1.0",
|
||||
"strip-ansi": "^6.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.21.3",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
|
||||
"integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs": {
|
||||
"version": "17.7.3",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.3.tgz",
|
||||
"integrity": "sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cliui": "^8.0.1",
|
||||
"escalade": "^3.1.1",
|
||||
"get-caller-file": "^2.0.5",
|
||||
"require-directory": "^2.1.1",
|
||||
"string-width": "^4.2.3",
|
||||
"y18n": "^5.0.5",
|
||||
"yargs-parser": "^21.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yargs-parser": {
|
||||
"version": "21.1.1",
|
||||
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
|
||||
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/yauzl": {
|
||||
"version": "2.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz",
|
||||
"integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-crc32": "~0.2.3",
|
||||
"fd-slicer": "~1.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/zod": {
|
||||
"version": "3.25.76",
|
||||
"resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
|
||||
"integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/colinhacks"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
14
packages/ui-docs/package.json
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"name": "ui-docs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"description": "UI walkthrough, screenshots, and review PDF for Verae Time × Zapier",
|
||||
"scripts": {
|
||||
"walk": "node scripts/walkthrough.mjs",
|
||||
"pdf": "python3 scripts/build-review-pdf.py"
|
||||
},
|
||||
"dependencies": {
|
||||
"puppeteer-core": "^24.15.0"
|
||||
}
|
||||
}
|
||||
BIN
packages/ui-docs/screenshots/01-console-fleet.png
Normal file
|
After Width: | Height: | Size: 391 KiB |
BIN
packages/ui-docs/screenshots/01b-console-fleet-overflow.png
Normal file
|
After Width: | Height: | Size: 394 KiB |
BIN
packages/ui-docs/screenshots/02-console-trace.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
packages/ui-docs/screenshots/02b-console-trace-run.png
Normal file
|
After Width: | Height: | Size: 285 KiB |
BIN
packages/ui-docs/screenshots/03-console-docs.png
Normal file
|
After Width: | Height: | Size: 210 KiB |
BIN
packages/ui-docs/screenshots/04-simulator.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
packages/ui-docs/screenshots/04b-simulator-run.png
Normal file
|
After Width: | Height: | Size: 334 KiB |
BIN
packages/ui-docs/screenshots/05-cs-credit.png
Normal file
|
After Width: | Height: | Size: 165 KiB |
BIN
packages/ui-docs/screenshots/05-cs-empty.png
Normal file
|
After Width: | Height: | Size: 107 KiB |
BIN
packages/ui-docs/screenshots/05-cs.png
Normal file
|
After Width: | Height: | Size: 160 KiB |
BIN
packages/ui-docs/screenshots/06-sales-empty.png
Normal file
|
After Width: | Height: | Size: 89 KiB |
BIN
packages/ui-docs/screenshots/06-sales.png
Normal file
|
After Width: | Height: | Size: 134 KiB |
BIN
packages/ui-docs/screenshots/07-accounting-empty.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
packages/ui-docs/screenshots/07-accounting.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
packages/ui-docs/screenshots/08-access-staff-credit.png
Normal file
|
After Width: | Height: | Size: 171 KiB |
BIN
packages/ui-docs/screenshots/08-access-staff-empty.png
Normal file
|
After Width: | Height: | Size: 106 KiB |
BIN
packages/ui-docs/screenshots/08-access-staff.png
Normal file
|
After Width: | Height: | Size: 166 KiB |
BIN
packages/ui-docs/screenshots/09-admin-login.png
Normal file
|
After Width: | Height: | Size: 322 KiB |
BIN
packages/ui-docs/screenshots/10-admin-rate-card.png
Normal file
|
After Width: | Height: | Size: 101 KiB |
BIN
packages/ui-docs/screenshots/11-admin-tiers.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
packages/ui-docs/screenshots/12-admin-customers.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
packages/ui-docs/screenshots/12b-admin-customer-drawer.png
Normal file
|
After Width: | Height: | Size: 92 KiB |
BIN
packages/ui-docs/screenshots/13-admin-statement.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
packages/ui-docs/screenshots/14-admin-invoices.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
BIN
packages/ui-docs/screenshots/15-admin-reports.png
Normal file
|
After Width: | Height: | Size: 95 KiB |
BIN
packages/ui-docs/screenshots/16-portal-login.png
Normal file
|
After Width: | Height: | Size: 322 KiB |
BIN
packages/ui-docs/screenshots/17-portal-dashboard.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
packages/ui-docs/screenshots/18-portal-invoices-empty.png
Normal file
|
After Width: | Height: | Size: 43 KiB |
BIN
packages/ui-docs/screenshots/19-portal-statement.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
packages/ui-docs/screenshots/20-portal-api-pricing.png
Normal file
|
After Width: | Height: | Size: 87 KiB |
BIN
packages/ui-docs/screenshots/21-swagger-stock.png
Normal file
|
After Width: | Height: | Size: 91 KiB |
BIN
packages/ui-docs/screenshots/22-catalog.png
Normal file
|
After Width: | Height: | Size: 948 KiB |
207
packages/ui-docs/scripts/build-review-pdf.py
Normal file
|
|
@ -0,0 +1,207 @@
|
|||
#!/usr/bin/env python3
|
||||
"""Build UI-REVIEW.pdf from walkthrough screenshots + report text."""
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.enums import TA_LEFT
|
||||
from reportlab.lib.pagesizes import letter
|
||||
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
|
||||
from reportlab.lib.units import inch
|
||||
from reportlab.platypus import (
|
||||
Image,
|
||||
PageBreak,
|
||||
Paragraph,
|
||||
SimpleDocTemplate,
|
||||
Spacer,
|
||||
Table,
|
||||
TableStyle,
|
||||
)
|
||||
|
||||
ROOT = Path(__file__).resolve().parents[1]
|
||||
SHOTS = ROOT / "screenshots"
|
||||
OUT = ROOT / "UI-REVIEW.pdf"
|
||||
|
||||
ACCENT = colors.HexColor("#4f46e5")
|
||||
INK = colors.HexColor("#171a26")
|
||||
MUTED = colors.HexColor("#6b7186")
|
||||
|
||||
PAGES = [
|
||||
("01-console-fleet.png", "Operator console — Fleet",
|
||||
"Open http://127.0.0.1:3850/. Role chips replace the truncated text field. Power is a status (on / paused / off), not a toggle. Replica and service actions live in the overflow menu."),
|
||||
("01b-console-fleet-overflow.png", "Fleet — replica overflow",
|
||||
"Click the overflow control on a replica. Pause, resume, and restart are in one menu. Confirm still guards restart."),
|
||||
("02-console-trace.png", "Operator console — Trace",
|
||||
"Trace tab. Orange box is fault inject only. Run step, then read hops on the right."),
|
||||
("02b-console-trace-run.png", "Trace after a run",
|
||||
"Hop names wrap. Module column no longer clips. Monitors sit under the console."),
|
||||
("03-console-docs.png", "Operator console — Docs",
|
||||
"Docs are cards matching Fleet, grouped High-level / Architecture / Remaining."),
|
||||
("04-simulator.png", "Standalone simulator",
|
||||
"http://127.0.0.1:3847/ uses the indigo shell. Orange is the Inject faults panel only."),
|
||||
("04b-simulator-run.png", "Simulator after a run",
|
||||
"Same hop grid as the console Trace tab. Run step or a scenario button."),
|
||||
("05-cs.png", "Customer service — review",
|
||||
"http://127.0.0.1:3011/. Enter a customer id, Review account. Amounts are dollars."),
|
||||
("05-cs-credit.png", "Customer service — credit applied",
|
||||
"Amount (USD) 5.00 → Apply credit. Prepaid and the credits table update in dollars."),
|
||||
("06-sales.png", "Sales — review",
|
||||
"http://127.0.0.1:3012/. Review account or Show quote. Quote is a named card, not a JSON dump."),
|
||||
("07-accounting.png", "Accounting — review",
|
||||
"http://127.0.0.1:3013/. Review plus QuickBooks IIF / CSV export buttons."),
|
||||
("08-access-staff.png", "Staff access plane",
|
||||
"http://127.0.0.1:3025/. Same indigo review/credit UI after authz."),
|
||||
("09-admin-login.png", "Admin — sign in",
|
||||
"http://127.0.0.1:3000/admin/. Seed user admin / admin-dev-key."),
|
||||
("10-admin-rate-card.png", "Admin — rate card",
|
||||
"Landing tab after sign-in. Per-endpoint list prices."),
|
||||
("12-admin-customers.png", "Admin — customers list",
|
||||
"Read-only table: name, email, type, billing. Edit opens the drawer."),
|
||||
("12b-admin-customer-drawer.png", "Admin — edit customer drawer",
|
||||
"Change email, type, multiplier override, billing. Save or Cancel."),
|
||||
("14-admin-invoices.png", "Admin — invoices empty state",
|
||||
"Illustrated empty state until a period is generated."),
|
||||
("16-portal-login.png", "Portal — sign in / create account",
|
||||
"http://127.0.0.1:3000/portal/. Create an account or sign in."),
|
||||
("17-portal-dashboard.png", "Portal — dashboard",
|
||||
"API key is masked. Reveal, Copy, or Regenerate. Copy puts the full key on the clipboard."),
|
||||
("18-portal-invoices-empty.png", "Portal — no invoices yet",
|
||||
"Empty-state illustration instead of a blank table row."),
|
||||
("19-portal-statement.png", "Portal — statement",
|
||||
"Prepaid, credits, usage, payments in dollars."),
|
||||
("20-portal-api-pricing.png", "Portal — API & pricing",
|
||||
"Notes that /docs is stock Swagger UI, not a designed customer surface."),
|
||||
("21-swagger-stock.png", "Swagger /docs (stock)",
|
||||
"Left as vendor Swagger. Do not treat it as the customer portal."),
|
||||
("22-catalog.png", "PDF catalog",
|
||||
"https://zapier.georgelambert.org/ uses system-ui on the indigo header, not Georgia."),
|
||||
]
|
||||
|
||||
|
||||
def styles():
|
||||
base = getSampleStyleSheet()
|
||||
return {
|
||||
"cover": ParagraphStyle("cover", parent=base["Title"], textColor=ACCENT, fontSize=22, leading=26, spaceAfter=12),
|
||||
"h1": ParagraphStyle("h1", parent=base["Heading1"], textColor=ACCENT, fontSize=16, leading=20, spaceBefore=8, spaceAfter=8),
|
||||
"h2": ParagraphStyle("h2", parent=base["Heading2"], textColor=INK, fontSize=13, leading=16, spaceBefore=6, spaceAfter=4),
|
||||
"body": ParagraphStyle("body", parent=base["BodyText"], textColor=INK, fontSize=10, leading=13, alignment=TA_LEFT, spaceAfter=6),
|
||||
"muted": ParagraphStyle("muted", parent=base["BodyText"], textColor=MUTED, fontSize=9, leading=12, spaceAfter=8),
|
||||
"cap": ParagraphStyle("cap", parent=base["BodyText"], textColor=MUTED, fontSize=8, leading=11, spaceAfter=10),
|
||||
}
|
||||
|
||||
|
||||
def header_footer(canvas, doc):
|
||||
canvas.saveState()
|
||||
canvas.setFillColor(ACCENT)
|
||||
canvas.rect(0, letter[1] - 18, letter[0], 18, fill=1, stroke=0)
|
||||
canvas.setFillColor(colors.white)
|
||||
canvas.setFont("Helvetica", 8)
|
||||
canvas.drawString(0.75 * inch, letter[1] - 13, "Verae Time x Zapier · UI review")
|
||||
canvas.setFillColor(MUTED)
|
||||
canvas.drawRightString(letter[0] - 0.75 * inch, 0.45 * inch, f"{doc.page}")
|
||||
canvas.restoreState()
|
||||
|
||||
|
||||
def p(text, style):
|
||||
return Paragraph(text.replace("&", "&"), style)
|
||||
|
||||
|
||||
def main():
|
||||
s = styles()
|
||||
story = []
|
||||
story.append(p("UI review report", s["cover"]))
|
||||
story.append(p("Walkthrough, screenshots, usage, remaining issues, and suggested improvements.", s["muted"]))
|
||||
story.append(p("Captured 2026-09-11. Browser console: no application errors after favicon data-URI (catalog static server still 404s a missing favicon.ico until the next full site deploy).", s["body"]))
|
||||
|
||||
story.append(p("What was fixed in this pass", s["h1"]))
|
||||
items = [
|
||||
"CS / sales / accounting / access-staff restyled to the portal indigo system. Dollars and names, not cents forms.",
|
||||
"Fleet replica and service actions collapsed to one overflow menu. Power column is status, not on/off toggles.",
|
||||
"Add-machine roles are chips. Header copy is operator LAN · binds 0.0.0.0:3850 (NATS stays private).",
|
||||
"Docs tab is cards. Trace hop grid wraps. Skip link and focus rings on staff and console.",
|
||||
"Simulator indigo; orange only on Inject faults.",
|
||||
"Portal API key masked with Reveal / Copy / Regenerate. Invoice empty-state illustration.",
|
||||
"Admin customers: list vs edit drawer. Invoice empty state.",
|
||||
"Catalog body font is system-ui. Swagger /docs labeled stock.",
|
||||
]
|
||||
for it in items:
|
||||
story.append(p("• " + it, s["body"]))
|
||||
|
||||
story.append(p("How to use each surface", s["h1"]))
|
||||
story.append(p("Operator: open :3850, Fleet for replicas, Trace to inject a Zap step, Docs for PDFs. Staff: CS :3011 credit in USD; Sales :3012 quote; Accounting :3013 export; Staff plane :3025 after authz. Customers: /portal. Ops: /admin. Lab: simulator :3847.", s["body"]))
|
||||
|
||||
story.append(p("Issues still to consider", s["h1"]))
|
||||
remaining = [
|
||||
["Severity", "Issue", "Suggestion"],
|
||||
["High", "Staff UIs look up by customer id; ledger often has no display name, so the heading is cust_1 not Ada.", "Join account-balance statements to zappier-edge customer name, or add a typeahead of customers."],
|
||||
["High", "Staff, portal, and admin have no session login on CS/sales/accounting HTML (LAN trust).", "Put a staff SSO or shared cookie in front of :3011–:3013 and :3025 before any non-lab bind."],
|
||||
["Med", "Catalog is still a long bibliography. Font is fixed; information architecture is not.", "Card index like the console Docs tab: Start here / Architecture / Modules."],
|
||||
["Med", "Swagger /docs remains stock.", "Keep it for integrators; do not skin it. Link it as 'OpenAPI explorer' only."],
|
||||
["Med", "Fleet add-machine form is dense; identity file still truncates in a narrow field.", "Two-row form: identity + roles on the second row with a file picker."],
|
||||
["Med", "lan-134 shows degraded/disabled in yellow while local/ns1 are green — correct, but the disable button looks like a fault.", "When a machine is intentionally disabled, use a neutral grey card, not degraded yellow."],
|
||||
["Low", "Portal statement empty cells still embed the empty illustration inside a table row.", "Drop the table when the list is empty; use the same card empty state as invoices."],
|
||||
["Low", "Overflow menus can open off-screen at the bottom of a long fleet table.", "Flip the menu upward when near the viewport edge."],
|
||||
["Low", "Access-staff and CS are nearly the same page.", "Keep both (plane vs department) but share one HTML template file."],
|
||||
["Low", "Simulator empty console is a large black void before the first run.", "Placeholder hop: 'Run a step to fill this trace.'"],
|
||||
]
|
||||
body = getSampleStyleSheet()["BodyText"]
|
||||
body.fontSize = 8
|
||||
body.leading = 10
|
||||
rows = []
|
||||
for i, row in enumerate(remaining):
|
||||
rows.append([Paragraph(f"<b>{c}</b>" if i == 0 else c, body) for c in row])
|
||||
grid = Table(rows, colWidths=[0.7 * inch, 2.6 * inch, 3.4 * inch], repeatRows=1)
|
||||
grid.setStyle(TableStyle([
|
||||
("BACKGROUND", (0, 0), (-1, 0), ACCENT),
|
||||
("TEXTCOLOR", (0, 0), (-1, 0), colors.white),
|
||||
("VALIGN", (0, 0), (-1, -1), "TOP"),
|
||||
("GRID", (0, 0), (-1, -1), 0.4, colors.HexColor("#e5e7f0")),
|
||||
("LEFTPADDING", (0, 0), (-1, -1), 6),
|
||||
("RIGHTPADDING", (0, 0), (-1, -1), 6),
|
||||
("TOPPADDING", (0, 0), (-1, -1), 5),
|
||||
("BOTTOMPADDING", (0, 0), (-1, -1), 5),
|
||||
("ROWBACKGROUNDS", (0, 1), (-1, -1), [colors.white, colors.HexColor("#f4f5fb")]),
|
||||
]))
|
||||
story.append(grid)
|
||||
story.append(PageBreak())
|
||||
|
||||
story.append(p("Screenshot atlas with usage notes", s["h1"]))
|
||||
max_w = 6.5 * inch
|
||||
max_h = 7.2 * inch
|
||||
for fname, title, how in PAGES:
|
||||
path = SHOTS / fname
|
||||
if not path.exists():
|
||||
story.append(p(f"Missing {fname}", s["muted"]))
|
||||
continue
|
||||
story.append(p(title, s["h2"]))
|
||||
story.append(p(how, s["body"]))
|
||||
img = Image(str(path))
|
||||
iw, ih = img.imageWidth, img.imageHeight
|
||||
scale = min(max_w / iw, max_h / ih)
|
||||
img.drawWidth = iw * scale
|
||||
img.drawHeight = ih * scale
|
||||
img.hAlign = "CENTER"
|
||||
story.append(img)
|
||||
story.append(p(fname, s["cap"]))
|
||||
story.append(PageBreak())
|
||||
|
||||
story.append(p("Revalidation", s["h1"]))
|
||||
story.append(p("Second full walkthrough after favicon, amount-column alignment, and Fleet form/overflow fixes: 32 screenshots, 0 application console errors. Surfaces are visually consistent (indigo, 12px radius, dollars). Tasks (review, credit, quote, edit customer, mask key, run trace) are obvious from primary buttons. Remaining work is identity join, staff auth, and catalog IA — listed above.", s["body"]))
|
||||
|
||||
doc = SimpleDocTemplate(
|
||||
str(OUT),
|
||||
pagesize=letter,
|
||||
leftMargin=0.75 * inch,
|
||||
rightMargin=0.75 * inch,
|
||||
topMargin=0.7 * inch,
|
||||
bottomMargin=0.7 * inch,
|
||||
title="Verae Time × Zapier UI review",
|
||||
author="UI-Docs",
|
||||
)
|
||||
doc.build(story, onFirstPage=header_footer, onLaterPages=header_footer)
|
||||
print(OUT)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
239
packages/ui-docs/scripts/walkthrough.mjs
Normal file
|
|
@ -0,0 +1,239 @@
|
|||
#!/usr/bin/env node
|
||||
/** Headless Chrome walkthrough: screenshots + console errors for every UI. */
|
||||
import fs from 'node:fs';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import puppeteer from 'puppeteer-core';
|
||||
|
||||
const ROOT = path.join(path.dirname(fileURLToPath(import.meta.url)), '..');
|
||||
const SHOTS = path.join(ROOT, 'screenshots');
|
||||
const LOG = path.join(ROOT, 'walkthrough-console.json');
|
||||
const CHROME =
|
||||
process.env.CHROME_PATH ||
|
||||
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome';
|
||||
|
||||
fs.mkdirSync(SHOTS, { recursive: true });
|
||||
|
||||
const errors = [];
|
||||
function note(pageName, type, text) {
|
||||
errors.push({ page: pageName, type, text: String(text).slice(0, 800) });
|
||||
}
|
||||
|
||||
const browser = await puppeteer.launch({
|
||||
executablePath: CHROME,
|
||||
headless: 'new',
|
||||
args: ['--no-sandbox', '--window-size=1440,900', '--disable-dev-shm-usage'],
|
||||
defaultViewport: { width: 1440, height: 900 },
|
||||
});
|
||||
|
||||
async function pageFor(name) {
|
||||
const page = await browser.newPage();
|
||||
page.on('pageerror', (err) => note(name, 'pageerror', err.message));
|
||||
page.on('console', (msg) => {
|
||||
if (msg.type() === 'error') note(name, 'console', msg.text());
|
||||
});
|
||||
page.on('response', (res) => {
|
||||
if (res.status() >= 500) note(name, 'http', `${res.status()} ${res.url()}`);
|
||||
});
|
||||
return page;
|
||||
}
|
||||
|
||||
async function shot(page, file) {
|
||||
await page.screenshot({ path: path.join(SHOTS, file), fullPage: true });
|
||||
}
|
||||
|
||||
async function safeGoto(page, url, name) {
|
||||
try {
|
||||
await page.goto(url, { waitUntil: 'networkidle2', timeout: 20000 });
|
||||
} catch (err) {
|
||||
note(name, 'goto', `${url} ${err.message}`);
|
||||
try {
|
||||
await page.goto(url, { waitUntil: 'domcontentloaded', timeout: 12000 });
|
||||
} catch (err2) {
|
||||
note(name, 'goto2', `${url} ${err2.message}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
// Operator console
|
||||
{
|
||||
const p = await pageFor('fleet');
|
||||
await safeGoto(p, 'http://127.0.0.1:3850/', 'fleet');
|
||||
await new Promise((r) => setTimeout(r, 1500));
|
||||
await shot(p, '01-console-fleet.png');
|
||||
const more = await p.$('.more-btn');
|
||||
if (more) {
|
||||
await more.click();
|
||||
await new Promise((r) => setTimeout(r, 300));
|
||||
await shot(p, '01b-console-fleet-overflow.png');
|
||||
await p.keyboard.press('Escape');
|
||||
}
|
||||
await p.click('nav button[data-tab="trace"]');
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await shot(p, '02-console-trace.png');
|
||||
const run = await p.$('#run');
|
||||
if (run) {
|
||||
await run.click();
|
||||
await new Promise((r) => setTimeout(r, 2500));
|
||||
await shot(p, '02b-console-trace-run.png');
|
||||
}
|
||||
await p.click('nav button[data-tab="docs"]');
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await shot(p, '03-console-docs.png');
|
||||
await p.close();
|
||||
}
|
||||
|
||||
// Simulator
|
||||
{
|
||||
const p = await pageFor('simulator');
|
||||
await safeGoto(p, 'http://127.0.0.1:3847/', 'simulator');
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
await shot(p, '04-simulator.png');
|
||||
const run = await p.$('#run');
|
||||
if (run) {
|
||||
await run.click();
|
||||
await new Promise((r) => setTimeout(r, 2500));
|
||||
await shot(p, '04b-simulator-run.png');
|
||||
}
|
||||
await p.close();
|
||||
}
|
||||
|
||||
// Staff UIs
|
||||
for (const [name, url, file, extra] of [
|
||||
['cs', 'http://127.0.0.1:3011/', '05-cs.png', true],
|
||||
['sales', 'http://127.0.0.1:3012/', '06-sales.png', false],
|
||||
['accounting', 'http://127.0.0.1:3013/', '07-accounting.png', false],
|
||||
['staff', 'http://127.0.0.1:3025/', '08-access-staff.png', true],
|
||||
]) {
|
||||
const p = await pageFor(name);
|
||||
await safeGoto(p, url, name);
|
||||
await shot(p, file.replace('.png', '-empty.png'));
|
||||
const btn = await p.$('button');
|
||||
if (btn) {
|
||||
await btn.click();
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
}
|
||||
await shot(p, file);
|
||||
if (extra) {
|
||||
const credit = await p.$('button[onclick="credit()"]');
|
||||
if (credit) {
|
||||
await credit.click();
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
await shot(p, file.replace('.png', '-credit.png'));
|
||||
}
|
||||
}
|
||||
await p.close();
|
||||
}
|
||||
|
||||
// Admin
|
||||
{
|
||||
const p = await pageFor('admin');
|
||||
await safeGoto(p, 'http://127.0.0.1:3000/admin/', 'admin');
|
||||
await shot(p, '09-admin-login.png');
|
||||
await p.type('#login-username', 'admin');
|
||||
await p.type('#login-password', 'admin-dev-key');
|
||||
await p.click('#login-form button[type="submit"]');
|
||||
await new Promise((r) => setTimeout(r, 1200));
|
||||
await shot(p, '10-admin-rate-card.png');
|
||||
const tabs = await p.$$('aside nav button');
|
||||
for (const [i, label] of [
|
||||
[1, '11-admin-tiers.png'],
|
||||
[2, '12-admin-customers.png'],
|
||||
[3, '13-admin-statement.png'],
|
||||
[4, '14-admin-invoices.png'],
|
||||
[5, '15-admin-reports.png'],
|
||||
]) {
|
||||
if (tabs[i]) {
|
||||
await tabs[i].click();
|
||||
await new Promise((r) => setTimeout(r, 600));
|
||||
await shot(p, label);
|
||||
}
|
||||
}
|
||||
const edit = await p.$('button[onclick^="openCustomerDrawer"]');
|
||||
if (edit) {
|
||||
await p.click('aside nav button[data-tab="customers"]');
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
const e2 = await p.$('button[onclick^="openCustomerDrawer"]');
|
||||
if (e2) {
|
||||
await e2.click();
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await shot(p, '12b-admin-customer-drawer.png');
|
||||
await p.evaluate(() => window.closeCustomerDrawer?.());
|
||||
}
|
||||
}
|
||||
await p.close();
|
||||
}
|
||||
|
||||
// Portal
|
||||
{
|
||||
const p = await pageFor('portal');
|
||||
await safeGoto(p, 'http://127.0.0.1:3000/portal/', 'portal');
|
||||
await shot(p, '16-portal-login.png');
|
||||
const toggle = await p.$('#auth-toggle');
|
||||
if (toggle) {
|
||||
await toggle.click();
|
||||
await new Promise((r) => setTimeout(r, 200));
|
||||
}
|
||||
const email = `walk+${Date.now()}@example.com`;
|
||||
const nameEl = await p.$('#auth-name');
|
||||
if (nameEl) await nameEl.type('Walkthrough User');
|
||||
await p.type('#auth-email', email);
|
||||
await p.type('#auth-password', 'Walkthrough1!');
|
||||
await p.click('#auth-submit');
|
||||
await new Promise((r) => setTimeout(r, 1500));
|
||||
await shot(p, '17-portal-dashboard.png');
|
||||
const invoices = await p.$('nav button[data-tab="invoices"]');
|
||||
if (invoices) {
|
||||
await invoices.click();
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await shot(p, '18-portal-invoices-empty.png');
|
||||
}
|
||||
const stmt = await p.$('nav button[data-tab="statement"]');
|
||||
if (stmt) {
|
||||
await stmt.click();
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await shot(p, '19-portal-statement.png');
|
||||
}
|
||||
const docs = await p.$('nav button[data-tab="docs"]');
|
||||
if (docs) {
|
||||
await docs.click();
|
||||
await new Promise((r) => setTimeout(r, 400));
|
||||
await shot(p, '20-portal-api-pricing.png');
|
||||
}
|
||||
await p.close();
|
||||
}
|
||||
|
||||
// Swagger (stock)
|
||||
{
|
||||
const p = await pageFor('swagger');
|
||||
await safeGoto(p, 'http://127.0.0.1:3000/docs', 'swagger');
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
await shot(p, '21-swagger-stock.png');
|
||||
await p.close();
|
||||
}
|
||||
|
||||
// Catalog (local if served, else public)
|
||||
{
|
||||
const p = await pageFor('catalog');
|
||||
const local = 'http://127.0.0.1:8765/';
|
||||
try {
|
||||
const r = await fetch(local, { signal: AbortSignal.timeout(1500) });
|
||||
await safeGoto(p, r.ok ? local : 'https://zapier.georgelambert.org/', 'catalog');
|
||||
} catch {
|
||||
await safeGoto(p, 'https://zapier.georgelambert.org/', 'catalog');
|
||||
}
|
||||
await new Promise((r) => setTimeout(r, 800));
|
||||
await shot(p, '22-catalog.png');
|
||||
await p.close();
|
||||
}
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
|
||||
const real = errors.filter((e) => !/favicon|Failed to load resource.*404/.test(e.text));
|
||||
fs.writeFileSync(LOG, JSON.stringify({ capturedAt: new Date().toISOString(), errors: real, all: errors }, null, 2));
|
||||
console.log(JSON.stringify({ shots: fs.readdirSync(SHOTS).length, errors: real.length }, null, 2));
|
||||
if (real.length) {
|
||||
for (const e of real) console.log(`ERR ${e.page} ${e.type}: ${e.text}`);
|
||||
}
|
||||
11
packages/ui-docs/walkthrough-console.json
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"capturedAt": "2026-09-11T21:58:47.138Z",
|
||||
"errors": [],
|
||||
"all": [
|
||||
{
|
||||
"page": "catalog",
|
||||
"type": "console",
|
||||
"text": "Failed to load resource: the server responded with a status of 404 (File not found)"
|
||||
}
|
||||
]
|
||||
}
|
||||