WP size: preset dropdown that sets the split threshold + show band in creator

Replaces the free-text "Typical WP Size" with a preset dropdown (Small /
Standard / Large / Custom). Choosing a preset auto-fills the max-hours split
threshold (still editable). The chosen band is now surfaced next to Est. Hrs
in the creator's size hint (not just the View-SOP modal), alongside the
threshold/over-threshold warning. Sample SOP aligned to Standard (80 hrs).
repopulateForm preserves a non-preset saved value as a dropdown option.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-15 16:17:18 -07:00
parent e5c450597a
commit 68c1c803d6
3 changed files with 42 additions and 11 deletions

View File

@@ -8,6 +8,21 @@ let allComments = [];
// project is active. Keeps each project's SOP separate in the browser.
function SK(base){ try { return (typeof ProjectData !== 'undefined' && ProjectData.key) ? ProjectData.key(base) : base; } catch(e){ return base; } }
// WP size presets — the dropdown label maps to a default split-threshold (max
// labor hours). The label is exported as governance.woSize (human-readable
// guidance); the number drives the Creator's "consider splitting" warning.
const WP_SIZE_PRESETS = {
'Small — 12 days (≈824 hrs)': 24,
'Standard — 35 days (≈4080 hrs)': 80,
'Large — 12 weeks (≈80160 hrs)': 160
};
function onSizePresetChange(){
const label = document.getElementById('gov_wosize').value;
const max = WP_SIZE_PRESETS[label];
if(max != null){ document.getElementById('gov_size_hours_max').value = max; }
// 'Custom…' / '' leave the threshold for manual entry.
}
let state = {
project: {name:'', number:'', client:'', division:'', site:''},
team: {pm:'', apm:'', cm:'', qm:''},
@@ -181,10 +196,10 @@ function loadSampleData(){
// Populate Step 5
document.getElementById('gov_woformat').value = 'WP##-[Sector]-[TYPE]';
document.getElementById('gov_wosize').value = '35 days / 4080 hours';
document.getElementById('gov_wosize').value = 'Standard — 35 days (≈4080 hrs)';
document.getElementById('gov_disciplines').value = 'Mechanical, Electrical, Tech';
document.getElementById('gov_discmode').value = 'choice';
document.getElementById('gov_size_hours_max').value = '120';
document.getElementById('gov_size_hours_max').value = '80';
// Populate Step 6
document.getElementById('qual_qcreq').value = 'Yes — Detailed inspection items';
@@ -246,6 +261,12 @@ function repopulateForm(){
if(state.signoffRoles[0]) set('role_super_name', state.signoffRoles[0].name);
if(state.signoffRoles[1]) set('role_foreman_name', state.signoffRoles[1].name);
set('gov_woformat', state.governance.woformat);
// gov_wosize is now a <select>; if a saved value isn't one of the presets
// (e.g. legacy free text), add it as an option so the round-trip preserves it.
const wsEl = document.getElementById('gov_wosize');
if(wsEl && state.governance.wosize && !Array.from(wsEl.options).some(o=>o.value===state.governance.wosize)){
wsEl.add(new Option(state.governance.wosize, state.governance.wosize));
}
set('gov_wosize', state.governance.wosize);
set('gov_disciplines', (state.governance.disciplines||[]).join(', '));
set('gov_discmode', state.governance.discMode);

View File

@@ -202,13 +202,20 @@
<div class="notice">A Work Package should be a manageable, trackable chunk of work — typically a 12 week assignment. The Creator warns the planner when a package exceeds the ceiling so it can be broken down.</div>
<div class="field-grid">
<div class="field">
<label>Typical WP Size (guidance)</label>
<input type="text" id="gov_wosize" placeholder="e.g., 35 days or 4080 hours">
<label>Typical WP Size</label>
<select id="gov_wosize" onchange="onSizePresetChange()">
<option value="">Select…</option>
<option value="Small — 12 days (≈824 hrs)">Small — 12 days (≈824 hrs)</option>
<option value="Standard — 35 days (≈4080 hrs)">Standard — 35 days (≈4080 hrs)</option>
<option value="Large — 12 weeks (≈80160 hrs)">Large — 12 weeks (≈80160 hrs)</option>
<option value="Custom…">Custom…</option>
</select>
<small>Sets the split threshold automatically; choose Custom to enter your own.</small>
</div>
<div class="field">
<label>Split threshold — max labor hours</label>
<input type="number" id="gov_size_hours_max" min="0" step="1" placeholder="e.g., 120">
<small>The Creator flags packages above this so they can be split (by discipline or scope).</small>
<input type="number" id="gov_size_hours_max" min="0" step="1" placeholder="e.g., 80">
<small>Auto-set from the size above (editable). The Creator flags packages over this so they can be split.</small>
</div>
</div>
</div>

View File

@@ -8,7 +8,7 @@ const SAMPLE_SOP = {
meta:{tool:'Work Package Configuration', sample:true},
project:{name:'Micron — INC Construction Work Packages', number:'26-67-008', client:'Micron Technology, Inc.', division:'Semiconductor', pm:'Nick Siegfried', cm:'K. Boyd', qm:'D. Nguyen', site:'Boise, ID — Fab'},
roles:[{role:'General Foreman',name:'M. Torres'},{role:'Superintendent',name:'K. Boyd'},{role:'Safety Manager / Lead',name:'A. Reyes'},{role:'Quality Manager',name:'D. Nguyen'},{role:'Planner',name:'L. Graver'}],
governance:{ issuance:['By Sector / Area','By Discipline'], woSize:'35 days', woFormat:'WP##-[Sector]-[TYPE]', disciplines:['Mechanical','Electrical','Tech'], discMode:'choice', instanceSuffix:'letter', sizeHoursMax:'120' },
governance:{ issuance:['By Sector / Area','By Discipline'], woSize:'Standard — 35 days (≈4080 hrs)', woFormat:'WP##-[Sector]-[TYPE]', disciplines:['Mechanical','Electrical','Tech'], discMode:'choice', instanceSuffix:'letter', sizeHoursMax:'80' },
woTypes:[
{name:'Conduit Install', enabled:true}, {name:'Tray Install', enabled:true},
{name:'Wire Pull', enabled:true}, {name:'Terminations', enabled:true},
@@ -372,12 +372,15 @@ function rollupDisciplineStatus(){
// ── WP SIZING WARNING (governance.sizeHoursMax) ──────────────────────────────
function onHoursChange(){
const el=document.getElementById('size-check'); if(!el) return;
const max=parseFloat((SOP&&SOP.governance&&SOP.governance.sizeHoursMax)||'');
const g=(SOP&&SOP.governance)||{};
const band=g.woSize?('Target: '+g.woSize+'. '):'';
const max=parseFloat(g.sizeHoursMax||'');
const hrs=parseFloat(gv('wp_hours'));
if(max && hrs && hrs>max){
el.innerHTML=`<span style="color:var(--accent-amber)">⚠ ${hrs} hrs exceeds the ${max}-hr split threshold — consider breaking this package down`+(isMultiDiscipline()?' (try <strong>Split by Discipline</strong>).':'.')+`</span>`;
} else if(max){ el.textContent=`Split threshold: ${max} hrs (from SOP).`; }
else { el.textContent=''; }
el.innerHTML=`<span style="color:var(--accent-amber)">${esc(band)}${hrs} hrs exceeds the ${max}-hr split threshold — consider breaking this package down`+(isMultiDiscipline()?' (try <strong>Split by Discipline</strong>).':'.')+`</span>`;
} else if(band || max){
el.innerHTML=`<span>${esc(band)}${max?'Split threshold: '+max+' hrs.':''}</span>`;
} else { el.textContent=''; }
}
// ── SPLIT BY DISCIPLINE ──────────────────────────────────────────────────────