Remove discipline from WP types; prep for firewall hosting + feedback collection
WP type discipline removal: - SOP WP Types step now has Enabled / Special Rules-Notes / WO Complete Approval columns (discipline column and DISCIPLINES/type-discipline maps gone) - WP Creator: drop the derived Discipline field, the type-trade number code, and discipline from saved packages and output; number tokens are now generic - Default WP number format no longer includes [Discipline] - Harden buildConstraints against object-shaped constraint names Firewall hosting: - Remove external Google Fonts @import; fall back to system fonts (no outbound calls, runs fully behind a firewall) Feedback collection: - Add shared feedback-config.js with a single FEEDBACK_ENDPOINT hook + best-effort postFeedback() (backend or Power Automate/SharePoint) - Add Export / Import to home and SOP feedback; wire central-post on all three surfaces (home, SOP step comments, WP review comments) - Add DEPLOYMENT.md documenting hosting and both feedback paths Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -21,19 +21,6 @@ let state = {
|
||||
let sop = null; // Generated SOP for WP tool
|
||||
|
||||
// ── LIBRARIES ─────────────────────────────────────────────────────────────────
|
||||
const DISCIPLINES = [
|
||||
'Conduit Installation',
|
||||
'Cable Tray Installation',
|
||||
'Instrument Raceway Installation',
|
||||
'Wire / Cable Pull',
|
||||
'Electrical/Instrument Cable Installation',
|
||||
'Cable Terminations',
|
||||
'Electrical Junction Box Installation',
|
||||
'Instrument Installation',
|
||||
'Control Panel Installation',
|
||||
'Heat Tracing Installation'
|
||||
];
|
||||
|
||||
const DEFAULT_WP_TYPES = [
|
||||
{name:'Rough-In', enabled:true},
|
||||
{name:'Mechanical Install', enabled:true},
|
||||
@@ -50,22 +37,6 @@ const DEFAULT_WP_TYPES = [
|
||||
{name:'Calibrations', enabled:false}
|
||||
];
|
||||
|
||||
const TYPE_DISCIPLINE_MAP = {
|
||||
'Rough-In':'Conduit Installation',
|
||||
'Mechanical Install':'Heat Tracing Installation',
|
||||
'Panel Install':'Control Panel Installation',
|
||||
'Conduit Install':'Conduit Installation',
|
||||
'Tray Install':'Cable Tray Installation',
|
||||
'Mechanical Tubing':'Heat Tracing Installation',
|
||||
'Instrument Install':'Instrument Installation',
|
||||
'Wire Pull':'Wire / Cable Pull',
|
||||
'Terminations':'Cable Terminations',
|
||||
'Prefab/Kitting':'Electrical Junction Box Installation',
|
||||
'Network Cabling':'Cable Tray Installation',
|
||||
'Fiber':'Wire / Cable Pull',
|
||||
'Calibrations':'Instrument Installation'
|
||||
};
|
||||
|
||||
const STANDARD_10_CONSTRAINTS = [
|
||||
{name:'Safety & Permitting', description:'Permits, safety reviews, environmental clearances'},
|
||||
{name:'Quality Control / Inspection', description:'QC approval, inspection readiness'},
|
||||
@@ -177,7 +148,7 @@ window.addEventListener('DOMContentLoaded',()=>{
|
||||
window.addEventListener('beforeunload', trackStepDwell);
|
||||
|
||||
function initializeWPTypes(){
|
||||
state.wpTypes = JSON.parse(JSON.stringify(DEFAULT_WP_TYPES)).map(t=>({...t,discipline:TYPE_DISCIPLINE_MAP[t.name]||''}));
|
||||
state.wpTypes = JSON.parse(JSON.stringify(DEFAULT_WP_TYPES)).map(t=>({...t,notes:'',approval:''}));
|
||||
renderWPTypes();
|
||||
}
|
||||
|
||||
@@ -201,7 +172,7 @@ function loadSampleData(){
|
||||
document.getElementById('role_foreman_name').value = 'Mike Jones';
|
||||
|
||||
// Populate Step 5
|
||||
document.getElementById('gov_woformat').value = 'WP##-[Sector]-[Discipline]-[TYPE]';
|
||||
document.getElementById('gov_woformat').value = 'WP##-[Sector]-[TYPE]';
|
||||
document.getElementById('gov_wosize').value = '3–5 days / 40–80 hours';
|
||||
|
||||
// Populate Step 6
|
||||
@@ -327,18 +298,20 @@ function updateProjectDisplay(){
|
||||
// ── RENDERING (SOP) ────────────────────────────────────────────────────────────
|
||||
function renderWPTypes(){
|
||||
const container = document.getElementById('wp-types-table');
|
||||
container.innerHTML = `<div style="padding:0.5rem; font-size:12px; font-weight:600; display:grid; grid-template-columns:30px 200px 200px; gap:1rem; margin-bottom:1rem; border-bottom:1px solid var(--border);">
|
||||
<div></div><div>Type</div><div>Discipline</div>
|
||||
container.innerHTML = `<div class="wp-types-header">
|
||||
<div>Work Order Type</div>
|
||||
<div style="text-align:center;">Enabled</div>
|
||||
<div>Special Rules / Notes</div>
|
||||
<div>WO Complete Approval</div>
|
||||
</div>`;
|
||||
state.wpTypes.forEach((t,i)=>{
|
||||
const row = document.createElement('div');
|
||||
row.className = 'wp-type-row';
|
||||
row.innerHTML = `
|
||||
<input type="checkbox" ${t.enabled?'checked':''} onchange="toggleWPType(${i})">
|
||||
<div>${t.name}</div>
|
||||
<select onchange="state.wpTypes[${i}].discipline=this.value">
|
||||
${DISCIPLINES.map(d=>`<option ${t.discipline===d?'selected':''}>${d}</option>`).join('')}
|
||||
</select>
|
||||
<div style="font-weight:600;">${t.name}</div>
|
||||
<div style="text-align:center;"><input type="checkbox" ${t.enabled?'checked':''} onchange="toggleWPType(${i})" style="width:18px; height:18px; cursor:pointer;"></div>
|
||||
<input type="text" placeholder="Special rules…" value="${(t.notes||'').replace(/"/g,'"')}" onchange="state.wpTypes[${i}].notes=this.value" style="padding:0.5rem; border:1px solid var(--border); border-radius:4px;">
|
||||
<input type="text" placeholder="PM / CM / QC…" value="${(t.approval||'').replace(/"/g,'"')}" onchange="state.wpTypes[${i}].approval=this.value" style="padding:0.5rem; border:1px solid var(--border); border-radius:4px;">
|
||||
`;
|
||||
container.appendChild(row);
|
||||
});
|
||||
@@ -660,7 +633,8 @@ function completeSOP(){
|
||||
woTypes: state.wpTypes.filter(t=>t.enabled).map(t=>({
|
||||
name: t.name,
|
||||
enabled: true,
|
||||
discipline: t.discipline || ''
|
||||
notes: t.notes || '',
|
||||
approval: t.approval || ''
|
||||
})),
|
||||
sources: state.sources.filter(s=>s.label),
|
||||
field: {trackPlatform: state.platforms.tracking},
|
||||
@@ -719,13 +693,50 @@ function submitComment(){
|
||||
|
||||
allComments.push(comment);
|
||||
localStorage.setItem('wp_suite_comments', JSON.stringify(allComments));
|
||||
|
||||
if(window.postFeedback) window.postFeedback({type:'sop_step_comment', ...comment});
|
||||
|
||||
document.getElementById('comment-text').value = '';
|
||||
document.getElementById('commenter-name').value = '';
|
||||
loadStepComments();
|
||||
alert('✓ Comment submitted!');
|
||||
}
|
||||
|
||||
function exportComments(){
|
||||
const saved = localStorage.getItem('wp_suite_comments');
|
||||
const data = saved ? JSON.parse(saved) : [];
|
||||
if(!data.length){ alert('No comments to export yet.'); return; }
|
||||
const payload = {app:'Work Package Suite', source:'sop', exportedAt:new Date().toISOString(), comments:data};
|
||||
const blob = new Blob([JSON.stringify(payload,null,2)], {type:'application/json'});
|
||||
const a = document.createElement('a');
|
||||
a.href = URL.createObjectURL(blob);
|
||||
a.download = 'wp-suite-comments-sop-' + new Date().toISOString().slice(0,10) + '.json';
|
||||
a.click();
|
||||
setTimeout(()=>URL.revokeObjectURL(a.href), 1000);
|
||||
}
|
||||
|
||||
function importComments(ev){
|
||||
const f = ev.target.files && ev.target.files[0];
|
||||
if(!f) return;
|
||||
const r = new FileReader();
|
||||
r.onload = ()=>{
|
||||
try{
|
||||
const inc = JSON.parse(r.result);
|
||||
const incoming = Array.isArray(inc) ? inc : (inc.comments || []);
|
||||
if(!incoming.length){ alert('No comments found in that file.'); return; }
|
||||
const saved = localStorage.getItem('wp_suite_comments');
|
||||
allComments = saved ? JSON.parse(saved) : [];
|
||||
const seen = new Set(allComments.map(c=>c.step+'|'+c.timestamp+'|'+c.text));
|
||||
let added = 0;
|
||||
incoming.forEach(c=>{ const k=c.step+'|'+c.timestamp+'|'+c.text; if(c.text && !seen.has(k)){ allComments.push(c); seen.add(k); added++; }});
|
||||
localStorage.setItem('wp_suite_comments', JSON.stringify(allComments));
|
||||
loadStepComments();
|
||||
alert('Imported ' + added + ' comment' + (added===1?'':'s') + '.');
|
||||
}catch(e){ alert('Could not read that file.'); }
|
||||
ev.target.value = '';
|
||||
};
|
||||
r.readAsText(f);
|
||||
}
|
||||
|
||||
function loadStepComments(){
|
||||
const saved = localStorage.getItem('wp_suite_comments');
|
||||
if(saved) allComments = JSON.parse(saved);
|
||||
|
||||
Reference in New Issue
Block a user