10 KiB
phase, plan, type, wave, depends_on, files_modified, autonomous, requirements, must_haves
| phase | plan | type | wave | depends_on | files_modified | autonomous | requirements | must_haves | ||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 09-ux-tech-debt-closure | 03 | execute | 1 |
|
true |
|
|
Purpose: Closes UX-03 — technicians can download each script individually from the printer detail page without going through the package export flow. Output: Three new API routes, three template links, two test cases.
Independent of 09-01 (no shared files). Can run in Wave 1 parallel with 09-01.
<execution_context> @C:/Users/SebastienQUEROL/.claude/get-shit-done/workflows/execute-plan.md @C:/Users/SebastienQUEROL/.claude/get-shit-done/templates/summary.md </execution_context>
@.planning/ROADMAP.md @.planning/phases/09-ux-tech-debt-closure/09-CONTEXT.md @.planning/phases/09-ux-tech-debt-closure/09-RESEARCH.md @.planning/phases/09-ux-tech-debt-closure/09-VALIDATION.md @imptune/api/scripts.py @imptune/templates/printer_detail.html @imptune/generators/script_generator.py @tests/test_packages.pyFrom imptune/api/scripts.py:
router = APIRouter(prefix="/printers")
def _get_printer_and_driver(printer_id: int):
"""Returns ((printer, driver, driver_name), None) on success or (None, PlainTextResponse) on error."""
...
@router.get("/{printer_id}/scripts/install")
def get_install_script(printer_id: int):
# validates, calls render_install(...), returns PlainTextResponse with
# Content-Disposition: attachment; filename="install.ps1"
...
@router.get("/{printer_id}/scripts/uninstall") # similar
@router.get("/{printer_id}/scripts/detect") # similar
From imptune/generators/script_generator:
render_install(printer_name, ip_address, port_name, driver_name, inf_filename, duplex_mode, color_mode, paper_size, collate) -> str
render_uninstall(printer_name, driver_name, port_name) -> str
render_detect(printer_name) -> str
Existing printer_detail.html Export section (lines 48-51):
<h2>Export</h2>
<a href="/printers/{{ printer.id }}/packages/ninja" role="button">Download NinjaRMM ZIP</a>
<a href="/printers/{{ printer.id }}/packages/intunewin" role="button">Download .intunewin</a>
Guard: the Export section is wrapped in {% if has_driver %} — the new Scripts section must be inside the same guard (no scripts without a driver).
Step 2 — Add `test_detail_page_shows_script_links` to `TestCommandPreview` (or a sibling class if more natural) in `tests/test_packages.py`. It should seed a printer with a driver, GET `/printers/{id}`, and assert the three `.ps1` href substrings.
Step 3 — Run tests. All new tests MUST go RED (routes don't exist, template links don't exist).
Commit: `test(09-03): add failing .ps1 route and detail-page link tests`
```python
def _install_response(printer_id: int):
result, error = _get_printer_and_driver(printer_id)
if error is not None:
return error
printer, driver, driver_name = result
rendered = render_install(
printer_name=printer.name,
ip_address=printer.ip_address,
port_name=printer.port_name,
driver_name=driver_name,
inf_filename=driver.inf_filename,
duplex_mode=printer.duplex_mode,
color_mode=printer.color_mode,
paper_size=printer.paper_size,
collate=printer.collate,
)
return PlainTextResponse(
content=rendered,
headers={"Content-Disposition": 'attachment; filename="install.ps1"'},
)
@router.get("/{printer_id}/scripts/install")
def get_install_script(printer_id: int):
return _install_response(printer_id)
@router.get("/{printer_id}/scripts/install.ps1")
def get_install_script_ps1(printer_id: int):
return _install_response(printer_id)
```
Repeat for uninstall and detect. Keeps the existing behavior untouched (existing routes still respond 200) while adding the `.ps1` URL shape locked in 09-CONTEXT.md.
FastAPI caveat: route paths with a `.` are valid — no special escaping needed. Confirm both routes register by checking `pytest --collect-only` imports scripts.py without error and the OpenAPI path table (if generated) lists both.
Step 2 — Edit `imptune/templates/printer_detail.html`. Inside the existing `{% if has_driver %}` block, immediately after the `</div>` closing the Uninstall command block (line 47) and BEFORE `<h2>Export</h2>` (line 48), add:
```html
<h2>Scripts</h2>
<a href="/printers/{{ printer.id }}/scripts/install.ps1" role="button" class="secondary">
Download Install Script
</a>
<a href="/printers/{{ printer.id }}/scripts/uninstall.ps1" role="button" class="secondary">
Download Uninstall Script
</a>
<a href="/printers/{{ printer.id }}/scripts/detect.ps1" role="button" class="secondary">
Download Detect Script
</a>
```
Do NOT touch the existing Export section — UX-03 requires scripts "in addition to" package exports.
Step 3 — Run tests. All 6 green.
Commit: `feat(09-03): add .ps1 script download routes and detail-page links`
<success_criteria>
- UX-03 observable truth achieved: technician on printer detail page clicks 3 direct download links and receives the individual .ps1 files
- Existing package export buttons remain untouched
- Existing extensionless script routes still work (backward compatible) </success_criteria>