diff --git a/playbook/startnet.cmd b/playbook/startnet.cmd index e0c6be4..d9d3ae4 100644 --- a/playbook/startnet.cmd +++ b/playbook/startnet.cmd @@ -85,6 +85,24 @@ if "%ges_choice%"=="7" set PCTYPE=gea-shopfloor-heattreat if "%ges_choice%"=="8" set PCTYPE=gea-shopfloor-waxtrace if "%ges_choice%"=="9" set PCTYPE=gea-shopfloor-display if "%PCTYPE%"=="" goto gea_shopfloor_submenu +if "%PCTYPE%"=="gea-shopfloor-display" goto display_submenu +goto enroll_menu + +:display_submenu +cls +echo. +echo ======================================== +echo Display Kiosk Sub-Type +echo ======================================== +echo. +echo 1. Dashboard (shop floor metrics dashboard) +echo 2. Lobby Display (lobby information screen) +echo. +set DISPLAYTYPE= +set /p disp_choice=Enter your choice (1-2): +if "%disp_choice%"=="1" set DISPLAYTYPE=Dashboard +if "%disp_choice%"=="2" set DISPLAYTYPE=Lobby +if "%DISPLAYTYPE%"=="" goto display_submenu goto enroll_menu :enroll_menu @@ -107,8 +125,8 @@ REM --- PPKG configuration (constructed at menu time, see docs) --- REM Vendor ships one source PPKG; we construct the BPRT-tagged filename REM by filling in Office, Region, Expiry, Version on the target copy. REM Update SOURCE_PPKG + PPKG_VER when a new PPKG is released. -set SOURCE_PPKG=GCCH_Prod_SFLD_v4.12.ppkg -set PPKG_VER=v4.12 +set SOURCE_PPKG=GCCH_Prod_SFLD_v4.14.ppkg +set PPKG_VER=v4.14 set PPKG_EXP=20260831 set REGION=US @@ -125,13 +143,12 @@ set PPKG= if not "%OFFICE%"=="" set PPKG=GCCH_Prod_SFLD_%OFFICE%_%REGION%_Exp_%PPKG_EXP%_%PPKG_VER%.ppkg REM --- 2026-05-04 rename reorg: PCTYPE is set by gea_shopfloor_submenu above -REM (single string, e.g. gea-shopfloor-collections). Old per-type submenus -REM (Standard sub-type, Display sub-type) are gone - flatten via the new -REM gea-shopfloor-* names. PCSUBTYPE / DISPLAYTYPE are no longer written -REM (pc-subtype.txt / display-type.txt deprecated). Configure-PC.ps1 still -REM looks up site-config.json profiles via the single full string. +REM (single string, e.g. gea-shopfloor-collections). pc-subtype.txt is no +REM longer written. DISPLAYTYPE IS still written (display-type.txt) when +REM PCTYPE=gea-shopfloor-display because Install-KioskApp.cmd needs Lobby +REM vs Dashboard to choose installer + Get-PCProfile builds Display-{type} +REM profile key. set PCSUBTYPE= -set DISPLAYTYPE= REM --- Machine number (collections + nocollections only; other variants don't use one) --- set MACHINENUM=9999 @@ -228,6 +245,15 @@ goto end :end echo. + +REM --- Push initial "WinPE staging" status to PXE webapp --- +REM Best-effort POST so the imaging dashboard shows this bay during the +REM WinPE / WIM-apply phase, BEFORE Run-ShopfloorSetup.ps1 takes over the +REM status updates post-PPKG. Identifies the session by BIOS serial. +REM Errors are swallowed - never block imaging on a status push. +for /f "tokens=2 delims==" %%S in ('wmic bios get serialnumber /value 2^>nul ^| find "="') do set BIOS_SERIAL=%%S +powershell -NoProfile -ExecutionPolicy Bypass -Command "try { $body = @{ serial=$env:BIOS_SERIAL; mac=((Get-NetAdapter -Physical | Where-Object { $_.Status -eq 'Up' } | Select-Object -First 1).MacAddress -replace '-',':'); pctype=$env:PCTYPE; current_stage='WinPE: PESetup / WIM apply'; stage_index=2; stage_total=8; status='in_progress' } | ConvertTo-Json -Compress; Invoke-WebRequest -Uri 'http://10.9.100.1:9009/imaging/status' -Method POST -Body $body -ContentType 'application/json' -UseBasicParsing -TimeoutSec 5 | Out-Null } catch { }" + echo Waiting for PESetup.exe to start... :wait_start ping -n 3 127.0.0.1 >NUL @@ -279,10 +305,11 @@ echo Manual fallback created at W:\enroll.cmd REM --- Copy shopfloor PC type setup scripts --- if "%PCTYPE%"=="" goto cleanup_enroll echo %PCTYPE%> W:\Enrollment\pc-type.txt -REM 2026-05-04 rename reorg: pc-subtype.txt and display-type.txt no longer -REM written. PCTYPE is a single full string ("gea-shopfloor-collections", -REM "gea-shopfloor-display", etc.). pcSubType-aware code paths fall back -REM to empty string and are handled as alias-resolution-only. +REM 2026-05-04 rename reorg: pc-subtype.txt no longer written. +REM display-type.txt IS still written for gea-shopfloor-display because +REM Install-KioskApp.cmd reads it to pick Lobby vs Dashboard installer +REM and Get-PCProfile.ps1 reads it to build the Display-{type} profile key. +if not "%DISPLAYTYPE%"=="" echo %DISPLAYTYPE%> W:\Enrollment\display-type.txt if not "%MACHINENUM%"=="" echo %MACHINENUM%> W:\Enrollment\machine-number.txt copy /Y "Y:\shopfloor-setup\Run-ShopfloorSetup.ps1" "W:\Enrollment\Run-ShopfloorSetup.ps1" REM --- Always copy Shopfloor baseline scripts --- @@ -299,6 +326,13 @@ if exist "Y:\shopfloor-setup\common" ( xcopy /E /Y /I "Y:\shopfloor-setup\common" "W:\Enrollment\shopfloor-setup\common\" echo Copied common setup files. ) +REM --- Copy _ntlars-backups (147 per-bay .reg files restored by gea-shopfloor-{collections,nocollections}\03-RestoreEDncConfig.ps1) --- +REM Same root level as common/, referenced by 03-RestoreEDncConfig.ps1 via Join-Path $PSScriptRoot '..\_ntlars-backups'. +if exist "Y:\shopfloor-setup\_ntlars-backups" ( + mkdir W:\Enrollment\shopfloor-setup\_ntlars-backups 2>NUL + xcopy /E /Y /I "Y:\shopfloor-setup\_ntlars-backups" "W:\Enrollment\shopfloor-setup\_ntlars-backups\" + echo Copied _ntlars-backups. +) REM --- Copy type-specific scripts on top of baseline --- if exist "Y:\shopfloor-setup\%PCTYPE%" ( mkdir "W:\Enrollment\shopfloor-setup\%PCTYPE%" 2>NUL diff --git a/webapp/services/imaging_status.py b/webapp/services/imaging_status.py index 138060e..1f2fc1b 100644 --- a/webapp/services/imaging_status.py +++ b/webapp/services/imaging_status.py @@ -66,12 +66,31 @@ def update_session(payload: dict) -> dict: except (json.JSONDecodeError, OSError): state = {} + # Reimage detection: if the new payload's stage_index is <= 1 and we have + # an existing session that was further along, treat this as a fresh run. + # Clear log_tail + reset started_at; preserve serial. Without this, a + # reimage on the same bay leaves stale "succeeded" / high-idx state on + # the dashboard until the new run progresses past idx 1. + if state: + try: + old_idx = int(state.get("stage_index") or 0) + new_idx = int(payload.get("stage_index") or 0) + except (TypeError, ValueError): + old_idx, new_idx = 0, 0 + rewind = new_idx > 0 and new_idx < old_idx and new_idx <= 1 + prev_done = state.get("status") in ("succeeded", "failed") + if rewind or (prev_done and new_idx > 0 and new_idx <= 1): + state = {"serial": serial, "previous_run_at": state.get("last_updated"), "log_tail": []} + if not state: state = { "serial": serial, "started_at": _now_iso(), "log_tail": [], } + elif "started_at" not in state: + # Fresh state after a rewind - mint a new started_at. + state["started_at"] = _now_iso() # Append any new log lines (preserve old; cap to LOG_TAIL_MAX). new_lines = payload.pop("log_lines", None)