Generic build for other GE sites: no WJ data, one shopfloor type, Windows USB builder
Everything West Jefferson specific moved out to a separate repo (pxe-site-wj): NTLARS/UDC/heat-treat backups keyed by WJ machine numbers, CMM and Wax/Trace bay lists, WJ OpenText profiles, site-config.json, the WJ preinstall list, and the WJ shopfloor PC types (Collections, NoCollections, Common, Keyence, CMM, Genspect, HeatTreat, Wax/Trace, Display, PartMarker) with GE-Enforce, machine numbers and the desktop layout. The part-marker bench tools moved to their own repo. Dead scripts removed: build-proxmox-iso, deploy-bios, sync_hardware_models, mirror-from-gold, pull-bios, startnet-template.cmd. Shopfloor is one generic type, gea-shopfloor-standard, with today's timing: - PPKG at first logon (unattend Order 10, unchanged). - Install-AppList.ps1 runs C:\PreInstall\preinstall.json during setup. - A new SYSTEM task, GE Shopfloor Post-PPKG, runs postppkg.json once after the post-PPKG reboot. It also clears AutoLogonCount after the ShopFloor handover (the Users-level monitor can be denied that HKLM write) and removes the Intune Sync task when done. - Both lists ship empty. A site adds entries and installers. - WinPE choice 3 goes straight to the PPKG menu. Staging, fetch and heal carry only the generic payload. The webapp's shopfloor sub-menu editor is gone, and the imaging tiles name the new stages. - The playbook deploys the empty lists only if missing. It now deploys the PowerShell 7 MSI the shopfloor unattend installs, which it never did before. Blancco site settings move into the webapp (Updates > Blancco releases): business location, licensing Wi-Fi SSID and password. They are rendered into the served preferences.xml and applied to every staged release, and are seeded from site-vars (site_name, blancco_wifi_ssid, blancco_wifi_password) only while none exist. The repo XML carries no site values; the plaintext Wi-Fi password is gone from it. New site_name and site_timezone settings: report and evidence-pack site name, server clock and webapp time zone. No more West Jefferson defaults in webapp/config.py or the dashboard title. Sync-BPRT.ps1 gets the server address filled in at download instead of WJ's GE address. USB on Windows: - scripts/Build-PxeUsb.ps1 runs the same checks as build-usb.sh. It writes one FAT32 CIDATA partition (ISO files plus patched grub.cfg plus payload) with diskpart and reads every file back by SHA-256. - Tested with Windows PowerShell 5.1 in the win11 VM, and the layout installs and first-boots in the pxetest VM. - scripts/stage-usb-share.sh stages the build folder on a share. - site-content/ is optional for both builders. KB docs/kb/How_To_Deploy_PXE_Server_New_Site.html: new-site deployment, Windows only, with a site-vars.yml guide. Checks: webapp tests pass (5 suites); the unattend lint and playbook syntax checks pass; every .ps1 parses; there are no WJ hosts, IPs, names or PC types in playbook/, webapp/, scripts/ or autoinstall/.
This commit is contained in:
@@ -179,8 +179,6 @@
|
||||
<li role="presentation"><button class="stn-tab active" id="tab-settings-btn" data-bs-toggle="tab" data-bs-target="#tab-settings" type="button" role="tab" aria-controls="tab-settings" aria-selected="true">Settings</button></li>
|
||||
<li role="presentation"><button class="stn-tab" id="tab-menu-btn" data-bs-toggle="tab" data-bs-target="#tab-menu" type="button" role="tab" aria-controls="tab-menu" aria-selected="false">Boot menu
|
||||
{% if boot_menu %}<span class="tab-count">{{ boot_menu | length }}</span>{% endif %}</button></li>
|
||||
<li role="presentation"><button class="stn-tab" id="tab-shopfloor-btn" data-bs-toggle="tab" data-bs-target="#tab-shopfloor" type="button" role="tab" aria-controls="tab-shopfloor" aria-selected="false">Shopfloor sub-menu
|
||||
{% if shopfloor_items %}<span class="tab-count">{{ shopfloor_items | length }}</span>{% endif %}</button></li>
|
||||
<li role="presentation"><button class="stn-tab" id="tab-raw-btn" data-bs-toggle="tab" data-bs-target="#tab-raw" type="button" role="tab" aria-controls="tab-raw" aria-selected="false">Raw
|
||||
{% if lint.errors %}{{ ui.chip(lint.errors | length ~ (' error' if lint.errors | length == 1 else ' errors'), 'err') }}
|
||||
{% elif lint.warnings %}{{ ui.chip(lint.warnings | length ~ (' warning' if lint.warnings | length == 1 else ' warnings'), 'warn') }}{% endif %}</button></li>
|
||||
@@ -265,31 +263,6 @@
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- ============================ SHOPFLOOR SUB-MENU ======================== -->
|
||||
<div class="tab-pane fade" id="tab-shopfloor" role="tabpanel" aria-labelledby="tab-shopfloor-btn">
|
||||
<section class="panel stn-pad" aria-labelledby="sfHead">
|
||||
<div class="stn-bar">
|
||||
<div class="grow"><h2 id="sfHead">Shopfloor sub-menu</h2>
|
||||
<div class="sub">menu.json on the enrollment share. No boot.wim edit.</div></div>
|
||||
<button type="button" class="ui-btn" id="sfAddBtn">Add item</button>
|
||||
<button type="submit" form="sfForm" class="ui-btn pri">Save shopfloor menu</button>
|
||||
</div>
|
||||
<div class="notice info" style="margin-top: 12px"><span>
|
||||
The GEA Shopfloor choice drills into this sub-menu. Each PC type must be an existing
|
||||
<span class="mono">shopfloor-setup/gea-shopfloor-*</span> handler. WinPE falls back to the
|
||||
built-in menu if the share or picker is unavailable. Rows without a label are dropped on save.</span>
|
||||
</div>
|
||||
<form action="{{ url_for('shopfloor_menu') }}" method="post" id="sfForm">
|
||||
<input type="hidden" name="_csrf_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" name="items" id="sfItemsData" value="[]">
|
||||
<div class="ed-list" id="sfTable">
|
||||
<div class="ed-hrow sf-grid" aria-hidden="true"><span>#</span><span class="ed-lab">Label</span><span class="ed-key">PC type (key)</span><span class="ed-hint">Hint</span><span class="ed-en">Shown</span><span></span></div>
|
||||
<div id="sfBody"><!-- rows injected by JS --></div>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
</div>
|
||||
|
||||
<!-- ================================= RAW ================================= -->
|
||||
<div class="tab-pane fade" id="tab-raw" role="tabpanel" aria-labelledby="tab-raw-btn">
|
||||
<div class="stn-cols">
|
||||
@@ -733,59 +706,4 @@
|
||||
})();
|
||||
</script>
|
||||
{% endif %}
|
||||
<script>
|
||||
(function(){
|
||||
const SF_AVAIL = {{ shopfloor_available | tojson }};
|
||||
const SF_ITEMS = {{ shopfloor_items | tojson }};
|
||||
const body = document.getElementById('sfBody');
|
||||
if (!body) return;
|
||||
const esc = s => String(s).replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
||||
const opts = sel => SF_AVAIL.map(k=>`<option value="${esc(k)}" ${k===sel?'selected':''}>${esc(k)}</option>`).join('');
|
||||
let uid = 0;
|
||||
// One line per item; Move up / Move down / Remove live in the row's "..." menu.
|
||||
function row(it){
|
||||
const r=document.createElement('div');
|
||||
r.className='ed-row sf-grid sf-row';
|
||||
const key=it.key||(SF_AVAIL[0]||'');
|
||||
const u=++uid;
|
||||
r.innerHTML =
|
||||
`<span class="ed-n sf-n"></span>`+
|
||||
`<div class="ed-lab"><label class="ed-cap" for="sfL${u}">Label</label><input class="field sf-label" id="sfL${u}" value="${esc(it.label||'')}" placeholder="Menu label"></div>`+
|
||||
`<div class="ed-key"><label class="ed-cap" for="sfK${u}">PC type (key)</label><select class="field sf-key" id="sfK${u}">${opts(key)}</select></div>`+
|
||||
`<div class="ed-hint"><label class="ed-cap" for="sfH${u}">Hint</label><input class="field sf-hint" id="sfH${u}" value="${esc(it.hint||'')}" placeholder="(optional)"></div>`+
|
||||
`<label class="ed-en"><input type="checkbox" class="sf-en" ${it.enabled===false?'':'checked'}><span class="ed-cap sf-en-txt" style="margin:0">Shown</span></label>`+
|
||||
`<div class="ed-act"><details class="more"><summary class="ui-btn ghost sf-more">⋯</summary><div class="menu">`+
|
||||
`<button type="button" class="sf-up">Move up</button><button type="button" class="sf-down">Move down</button>`+
|
||||
`<div class="sep"></div><button type="button" class="sf-rm del">Remove item</button></div></details></div>`;
|
||||
return r;
|
||||
}
|
||||
const rows=()=>[...body.querySelectorAll('.sf-row')];
|
||||
const renum=()=>rows().forEach((r,i,all)=>{
|
||||
const n=i+1;
|
||||
r.querySelector('.sf-n').textContent=n;
|
||||
r.querySelector('.sf-label').setAttribute('aria-label','Item '+n+' label');
|
||||
r.querySelector('.sf-key').setAttribute('aria-label','Item '+n+' PC type');
|
||||
r.querySelector('.sf-hint').setAttribute('aria-label','Item '+n+' hint');
|
||||
r.querySelector('.sf-en').setAttribute('aria-label','Item '+n+' shown in menu');
|
||||
r.querySelector('.sf-more').setAttribute('aria-label','More actions for item '+n);
|
||||
r.querySelector('.sf-up').disabled = i===0;
|
||||
r.querySelector('.sf-down').disabled = i===all.length-1;
|
||||
});
|
||||
const add=it=>{body.appendChild(row(it||{}));renum();};
|
||||
body.addEventListener('click',e=>{
|
||||
const r=e.target.closest('.sf-row'); if(!r)return;
|
||||
const menu=r.querySelector('details.more');
|
||||
if(e.target.closest('.sf-rm')){r.remove();renum();}
|
||||
else if(e.target.closest('.sf-up')&&r.previousElementSibling){r.parentNode.insertBefore(r,r.previousElementSibling);renum();menu.removeAttribute('open');menu.querySelector('summary').focus();}
|
||||
else if(e.target.closest('.sf-down')&&r.nextElementSibling){r.parentNode.insertBefore(r.nextElementSibling,r);renum();menu.removeAttribute('open');menu.querySelector('summary').focus();}
|
||||
});
|
||||
document.getElementById('sfAddBtn').addEventListener('click',()=>{add({});const l=body.lastElementChild.querySelector('.sf-label');if(l)l.focus();});
|
||||
document.getElementById('sfForm').addEventListener('submit',()=>{
|
||||
const items=rows().map(r=>({label:r.querySelector('.sf-label').value.trim(),key:r.querySelector('.sf-key').value,hint:r.querySelector('.sf-hint').value.trim(),enabled:r.querySelector('.sf-en').checked})).filter(x=>x.label&&x.key);
|
||||
document.getElementById('sfItemsData').value=JSON.stringify(items);
|
||||
});
|
||||
(SF_ITEMS.length?SF_ITEMS:[]).forEach(add);
|
||||
if(!rows().length) add({});
|
||||
})();
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user