From 2af4b58a9e271ffdbc605cc5e10fb206a0195ada Mon Sep 17 00:00:00 2001 From: "n.siegfried" Date: Thu, 11 Jun 2026 14:57:53 -0700 Subject: [PATCH] Consolidate suite into two tools; restore Rev 0 features - Home page: two cards (SOP Configuration / Work Package Creator); SOP card turns green + "Review" once complete (persisted to localStorage), WP card locked until SOP is done - Header: white background with dark text; remove duplicate title next to logo - Move Step Comments toggle into the header; restore Usage Logs analytics - Load Sample: project MICRON_PH1_CUP_HPM_FMCS INSTALL, PM Mariano Sanchez - Team tab: add Assistant Project Manager + repeatable "Add Team Member" - Sign-Offs: add Assistant Project Manager to additional roles - Sequencing: restore Rev 0 pre-sequenced drag-and-drop (gates, arrows) - Sources: restore Rev 0 pre-loaded list; defaults are deletable + addable - WP Creator: replace broken stub with the real creator embedded in the WP tab, auto-loading the completed SOP from localStorage - Remove duplicate standalone SOP tool (sop-config-*) Co-Authored-By: Claude Opus 4.8 (1M context) --- index.html | 83 +++-- sop-config-app.js | 587 ---------------------------------- sop-config-styles.css | 507 ----------------------------- sop-config-tool.html | 309 ------------------ work-package-suite-app.js | 305 ++++++++++++++++-- work-package-suite-styles.css | 106 ++++-- work-package-suite.html | 76 +++-- wp-creation-app.js | 15 +- wp-creation-index.html | 6 +- wp-creation-styles.css | 4 + 10 files changed, 484 insertions(+), 1514 deletions(-) delete mode 100644 sop-config-app.js delete mode 100644 sop-config-styles.css delete mode 100644 sop-config-tool.html diff --git a/index.html b/index.html index 4506d17..b6fea4b 100644 --- a/index.html +++ b/index.html @@ -167,6 +167,25 @@ .card-button:hover { background: var(--cds-hover-primary); } + + /* COMPLETE STATE (SOP done) */ + .card.complete { + background: #ecfdf5; + border-color: #16a34a; + } + .card.complete .card-button { background: #16a34a; } + .card.complete .card-button:hover { background: #15803d; } + .card-status { + display: inline-block; + font-size: 12px; + font-weight: 600; + color: #16a34a; + margin-bottom: 0.5rem; + } + .card.disabled { + opacity: 0.6; + pointer-events: none; + } /* SECTION */ .section { @@ -365,27 +384,19 @@ @@ -394,9 +405,9 @@

Getting Started

    -
  1. Click "Unified Suite" to begin
  2. -
  3. Complete the 10-step SOP Configuration for your project (~15 minutes)
  4. -
  5. Switch to "Work Package Creation" tab to start authoring Work Packages
  6. +
  7. Open "SOP Configuration" and complete the 10 steps for your project (~15 minutes)
  8. +
  9. Finish the SOP — this card turns green and unlocks the Work Package Creator
  10. +
  11. Open "Work Package Creator" to author Work Packages with your SOP defaults pre-populated
  12. Leave feedback on any page using the feedback button below
@@ -426,8 +437,8 @@

About This Suite

-

Three Complementary Tools

-

Unified workflow for end-to-end SOP+WP creation, standalone SOP generator, and individual WP authoring. Choose the approach that fits your workflow.

+

Two-Step Workflow

+

Configure the project SOP once, then author every Work Package against it. The Creator stays locked until the SOP is complete, so packages always inherit a valid baseline.

Leave Feedback

@@ -448,8 +459,36 @@ - - diff --git a/work-package-suite-app.js b/work-package-suite-app.js index 636b2d3..5bba011 100644 --- a/work-package-suite-app.js +++ b/work-package-suite-app.js @@ -6,7 +6,8 @@ let allComments = []; let state = { project: {name:'', number:'', client:'', division:'', site:''}, - team: {pm:'', cm:'', qm:''}, + team: {pm:'', apm:'', cm:'', qm:''}, + teamMembers: [], signoffRoles: [{role:'Superintendent',name:''},{role:'Foreman',name:''}], wpTypes: [], governance: {woformat:'', wosize:'', issuance:[]}, @@ -94,6 +95,7 @@ const CONSTRAINT_LIBRARY = [ ]; const OPTIONAL_ROLES = [ + 'Assistant Project Manager', 'General Foreman', 'Construction Manager', 'HSE Professional', @@ -148,13 +150,31 @@ const LABOR_COST_CODES = [ // ── INITIALIZATION ──────────────────────────────────────────────────────────── window.addEventListener('DOMContentLoaded',()=>{ initializeWPTypes(); + renderTeamMembers(); renderOptionalRoles(); renderStandardConstraints(); renderSequenceSteps(); renderSources(); + restoreSavedSOP(); updateStepUI(); updateProjectDisplay(); + + // Deep-link: ?tab=sop | ?tab=wp from the home page cards. + const params = new URLSearchParams(window.location.search); + const tab = params.get('tab'); + if(tab === 'wp' || tab === 'sop') switchTool(tab); + + track('app_open'); + let _fieldTimer; + document.addEventListener('input', e=>{ + const t = e.target; + if(t && t.id && /^(INPUT|SELECT|TEXTAREA)$/.test(t.tagName)){ + clearTimeout(_fieldTimer); + _fieldTimer = setTimeout(()=> track('field_edit', {field:t.id}), 600); + } + }); }); +window.addEventListener('beforeunload', trackStepDwell); function initializeWPTypes(){ state.wpTypes = JSON.parse(JSON.stringify(DEFAULT_WP_TYPES)).map(t=>({...t,discipline:TYPE_DISCIPLINE_MAP[t.name]||''})); @@ -164,14 +184,15 @@ function initializeWPTypes(){ // ── LOAD SAMPLE DATA ────────────────────────────────────────────────────────── function loadSampleData(){ // Populate Step 1 - document.getElementById('proj_name').value = 'Micron — INC Construction Work Packages'; + document.getElementById('proj_name').value = 'MICRON_PH1_CUP_HPM_FMCS INSTALL'; document.getElementById('proj_number').value = '26-67-008'; document.getElementById('proj_client').value = 'Micron Technology, Inc.'; document.getElementById('proj_division').value = 'Semiconductor'; document.getElementById('proj_site').value = 'Boise, ID — Fab 7'; - + // Populate Step 2 - document.getElementById('proj_pm').value = 'Nick Siegfried'; + document.getElementById('proj_pm').value = 'Mariano Sanchez'; + document.getElementById('proj_apm').value = 'Assistant PM'; document.getElementById('proj_cm').value = 'K. Boyd'; document.getElementById('proj_qm').value = 'D. Nguyen'; @@ -192,7 +213,8 @@ function loadSampleData(){ // Collect all data collectStepData(); - + track('sample_loaded'); + alert('✓ Sample data loaded!\n\nNavigate through the SOP steps to see example values. You can edit or replace any field.'); // Switch to step 1 @@ -201,6 +223,55 @@ function loadSampleData(){ updateProjectDisplay(); } +// ── RESTORE A COMPLETED SOP (for "Review" + WP tab across reloads) ───────────── +function restoreSavedSOP(){ + let savedState = null, savedSop = null, complete = false; + try { + complete = localStorage.getItem('wp_suite_sop_complete') === '1'; + savedState = JSON.parse(localStorage.getItem('wp_suite_state') || 'null'); + savedSop = JSON.parse(localStorage.getItem('wp_suite_sop') || 'null'); + } catch(e){} + if(!complete || !savedState) return; + + state = savedState; + sop = savedSop; + sopComplete = true; + + // Re-render dynamic lists from restored state. + renderWPTypes(); + renderTeamMembers(); + renderOptionalRoles(); + renderStandardConstraints(); + renderSequenceSteps(); + renderSources(); + repopulateForm(); + + if(typeof onSOPReady === 'function') onSOPReady(sop); +} + +// Push restored state values back into the static form inputs. +function repopulateForm(){ + const set = (id,val)=>{ const el=document.getElementById(id); if(el!=null && val!=null) el.value = val; }; + set('proj_name', state.project.name); + set('proj_number', state.project.number); + set('proj_client', state.project.client); + set('proj_division', state.project.division); + set('proj_site', state.project.site); + set('proj_pm', state.team.pm); + set('proj_apm', state.team.apm); + set('proj_cm', state.team.cm); + set('proj_qm', state.team.qm); + 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); + set('gov_wosize', state.governance.wosize); + set('qual_qcreq', state.quality.qcreq); + set('qual_photo', state.quality.photo); + set('qual_hold', state.quality.hold); + set('plat_tracking', state.platforms.tracking); + set('plat_commissioning', state.platforms.commissioning); +} + // ── TOOL SWITCHING ──────────────────────────────────────────────────────────── function switchTool(tool){ currentTool = tool; @@ -219,11 +290,34 @@ function switchTool(tool){ }else{ document.getElementById('total-steps').textContent = '—'; } - + + if(tool === 'wp') renderWPTab(); + updateStepUI(); updateProjectDisplay(); } +// Show the gate or the embedded Work Package Creator depending on SOP status. +function renderWPTab(){ + const gate = document.getElementById('wp-gate'); + const frame = document.getElementById('wp-frame'); + if(!gate || !frame) return; + if(sopComplete){ + gate.style.display = 'none'; + frame.style.display = 'block'; + // Reload each time so the creator picks up the latest SOP from localStorage. + frame.src = 'wp-creation-index.html?embedded=1&t=' + Date.now(); + }else{ + gate.style.display = 'block'; + frame.style.display = 'none'; + } +} + +// Called from completeSOP / restoreSavedSOP once an SOP is available. +function onSOPReady(){ + if(currentTool === 'wp') renderWPTab(); +} + function updateProjectDisplay(){ const projName = document.getElementById('proj_name')?.value || 'Project'; const display = document.getElementById('project-display'); @@ -255,6 +349,28 @@ function toggleWPType(i){ renderWPTypes(); } +function renderTeamMembers(){ + const container = document.getElementById('team-members-list'); + if(!container) return; + container.innerHTML = state.teamMembers.map((m,i)=>` +
+ + + +
+ `).join(''); +} + +function addTeamMember(){ + state.teamMembers.push({role:'',name:''}); + renderTeamMembers(); +} + +function removeTeamMember(i){ + state.teamMembers.splice(i,1); + renderTeamMembers(); +} + function renderOptionalRoles(){ const container = document.getElementById('optional-roles-list'); const current = state.signoffRoles.filter(r=>r.role!=='Superintendent'&&r.role!=='Foreman'); @@ -323,38 +439,86 @@ function addCustomConstraint(name){ renderStandardConstraints(); } +const DEFAULT_SEQUENCE = ['Layout','Conduit Install','Tray Install','Wire Pull','Device Install','Termination','QC Inspection','Commissioning']; + +let seqDragIndex = null; function renderSequenceSteps(){ const container = document.getElementById('sequence-list'); - if(!state.sequence.length) state.sequence = [{label:'Layout',kind:'step'},{label:'Installation',kind:'step'},{label:'Testing',kind:'step'},{label:'Commissioning',kind:'step'}]; - container.innerHTML = state.sequence.map((s,i)=>` -
- - - -
- `).join(''); + if(!container) return; + if(!state.sequence.length) state.sequence = DEFAULT_SEQUENCE.map(s=>({label:s,kind:'step'})); + container.innerHTML = ''; + let stepNo = 0; + state.sequence.forEach((item,i)=>{ + const isGate = item.kind==='gate'; + if(!isGate) stepNo++; + const row = document.createElement('div'); + row.className = 'seq-step' + (isGate?' gate':''); + row.draggable = true; + row.dataset.idx = i; + const badge = isGate ? `◆ HOLD` + : `${stepNo}`; + row.innerHTML = ` + + ${badge} + + `; + row.addEventListener('dragstart',e=>{ seqDragIndex=i; row.classList.add('dragging'); e.dataTransfer.effectAllowed='move'; }); + row.addEventListener('dragend',()=>{ row.classList.remove('dragging'); document.querySelectorAll('.seq-step').forEach(s=>s.classList.remove('drag-over')); }); + row.addEventListener('dragover',e=>{ e.preventDefault(); row.classList.add('drag-over'); e.dataTransfer.dropEffect='move'; }); + row.addEventListener('dragleave',()=>row.classList.remove('drag-over')); + row.addEventListener('drop',e=>{ + e.preventDefault(); row.classList.remove('drag-over'); + const from=seqDragIndex, to=i; + if(from===null||from===to) return; + const moved=state.sequence.splice(from,1)[0]; + state.sequence.splice(to,0,moved); + seqDragIndex=null; renderSequenceSteps(); + }); + container.appendChild(row); + if(i({label:s.label, system:'', notes:'', link:'', ph:s.ph})); container.innerHTML = state.sources.map((s,i)=>`
- + @@ -390,6 +554,8 @@ function previousStep(){ } function updateStepUI(){ + trackStepDwell(); + track('step_view', {step: currentStep}); // SOP steps document.querySelectorAll('[id^="sop-step-"]').forEach(s=>s.style.display='none'); document.getElementById(`sop-step-${currentStep}`)?.style.display && (document.getElementById(`sop-step-${currentStep}`).style.display='block'); @@ -421,6 +587,7 @@ function collectStepData(){ break; case 2: state.team.pm = document.getElementById('proj_pm').value; + state.team.apm = document.getElementById('proj_apm').value; state.team.cm = document.getElementById('proj_cm').value; state.team.qm = document.getElementById('proj_qm').value; break; @@ -478,9 +645,11 @@ function completeSOP(){ client: state.project.client, division: state.project.division, pm: state.team.pm, + apm: state.team.apm, cm: state.team.cm, qm: state.team.qm, - site: state.project.site + site: state.project.site, + teamMembers: state.teamMembers.filter(m=>(m.role||m.name)) }, roles: state.signoffRoles.filter(r=>r.role), governance: { @@ -512,12 +681,20 @@ function completeSOP(){ sopComplete = true; updateProjectDisplay(); - + + // Persist for the home page (green / "Review") and for the WP Creator tab. + try { + localStorage.setItem('wp_suite_sop', JSON.stringify(sop)); + localStorage.setItem('wp_suite_state', JSON.stringify(state)); + localStorage.setItem('wp_suite_sop_complete', '1'); + } catch(e){} + + track('sop_generated', {woTypes: sop.woTypes.length, constraints: sop.constraints.length}); + alert('✓ SOP Configuration Complete!\n\nSwitch to "Work Package Creation" to start creating Work Packages.'); - - // Update WP tool status - document.getElementById('sop-status').textContent = '✓ Ready'; - document.getElementById('sop-progress-text').textContent = `Project: ${sop.project.name} | ${sop.woTypes.length} WP Types | ${sop.constraints.length} Constraints`; + + // Hand the SOP to the embedded Work Package Creator and unlock its tab. + if(typeof onSOPReady === 'function') onSOPReady(sop); } // ── COMMENTS ────────────────────────────────────────────────────────────────── @@ -552,10 +729,10 @@ function submitComment(){ function loadStepComments(){ const saved = localStorage.getItem('wp_suite_comments'); if(saved) allComments = JSON.parse(saved); - + const stepComments = allComments.filter(c=>c.step===currentStep); const list = document.getElementById('comments-list'); - + if(stepComments.length === 0){ list.innerHTML = '
No comments yet on this step.
'; }else{ @@ -567,3 +744,65 @@ function loadStepComments(){ `).join(''); } } + +// ── USAGE ANALYTICS ───────────────────────────────────────────────────────── +// Lightweight usage analytics stored in localStorage so the tool owner can review +// engagement over time. No field VALUES are stored (field-edit events record only +// the field id), keeping captured data non-sensitive. +const ANALYTICS_KEY = 'wp_suite_analytics_v1'; +let _stepEnter = Date.now(); +const _session = 's_' + Date.now().toString(36) + Math.random().toString(36).slice(2,6); + +function analyticsLoad(){ + try { return JSON.parse(localStorage.getItem(ANALYTICS_KEY)) || {events:[]}; } + catch(e){ return {events:[]}; } +} +function analyticsSave(data){ + try { localStorage.setItem(ANALYTICS_KEY, JSON.stringify(data)); } + catch(e){ /* storage unavailable — degrade silently */ } +} +function track(event, detail){ + try { + const data = analyticsLoad(); + data.events.push({ ts: new Date().toISOString(), session: _session, event, detail: detail||null }); + if(data.events.length > 5000) data.events = data.events.slice(-5000); + analyticsSave(data); + } catch(e){} +} +function trackStepDwell(){ + const ms = Date.now() - _stepEnter; + if(ms > 400 && ms < 1000*60*60) track('step_dwell', {step: currentStep, ms}); + _stepEnter = Date.now(); +} +function analyticsSummary(){ + const data = analyticsLoad(); + const byEvent = {}, byStep = {}, dwell = {}, sessions = new Set(); + data.events.forEach(e=>{ + byEvent[e.event] = (byEvent[e.event]||0)+1; + sessions.add(e.session); + if(e.event==='step_view' && e.detail) byStep[e.detail.step]=(byStep[e.detail.step]||0)+1; + if(e.event==='step_dwell' && e.detail){ dwell[e.detail.step]=(dwell[e.detail.step]||0)+e.detail.ms; } + }); + return {total:data.events.length, sessions:sessions.size, byEvent, byStep, dwell, first:data.events[0]?.ts, last:data.events[data.events.length-1]?.ts}; +} +function showAnalytics(){ + const s = analyticsSummary(); + const fmtMin = ms => (ms/60000).toFixed(1)+' min'; + let txt = `USAGE LOGS\n\nSessions: ${s.sessions} Events: ${s.total}\nRange: ${s.first?new Date(s.first).toLocaleString():'—'} → ${s.last?new Date(s.last).toLocaleString():'—'}\n\nStep views:\n`; + for(let i=1;i<=10;i++) txt += ` Step ${i}: ${s.byStep[i]||0} views` + (s.dwell[i]?`, ${fmtMin(s.dwell[i])} total`:'') + `\n`; + txt += `\nActions:\n`; + Object.keys(s.byEvent).filter(k=>!['step_view','step_dwell','field_edit'].includes(k)).forEach(k=> txt += ` ${k}: ${s.byEvent[k]}\n`); + txt += ` field edits: ${s.byEvent['field_edit']||0}\n`; + txt += `\nDownload full event log as JSON?`; + if(confirm(txt)) downloadAnalytics(); +} +function downloadAnalytics(){ + const data = analyticsLoad(); + const blob = new Blob([JSON.stringify(data,null,2)], {type:'application/json'}); + const a = document.createElement('a'); + a.href = URL.createObjectURL(blob); + a.download = 'wp-suite-usage-' + new Date().toISOString().slice(0,10) + '.json'; + a.click(); + URL.revokeObjectURL(a.href); + track('analytics_exported'); +} diff --git a/work-package-suite-styles.css b/work-package-suite-styles.css index 3d233bc..406a55a 100644 --- a/work-package-suite-styles.css +++ b/work-package-suite-styles.css @@ -30,17 +30,18 @@ body { /* HEADER */ .header { - background: linear-gradient(135deg, var(--primary) 0%, #1e40af 100%); - color: white; + background: #ffffff; + color: var(--text); padding: 1.5rem 2rem; display: flex; justify-content: space-between; align-items: center; - box-shadow: var(--shadow-lg); + box-shadow: var(--shadow); + border-bottom: 1px solid var(--border); } -.header-left { - flex: 1; +.header-left { + flex: 1; display: flex; align-items: center; gap: 1.5rem; @@ -51,18 +52,18 @@ body { align-items: center; gap: 0.5rem; text-decoration: none; - color: white; + color: var(--text); font-weight: 700; font-size: 14px; transition: opacity 0.2s; } -.logo:hover { opacity: 0.9; } +.logo:hover { opacity: 0.7; } .logo-icon { width: 36px; height: 36px; - background: rgba(255,255,255,0.2); + background: var(--primary-light); border-radius: 6px; display: flex; align-items: center; @@ -71,22 +72,16 @@ body { font-weight: 700; } -.logo-text { - display: flex; - flex-direction: column; - line-height: 1; - font-size: 12px; -} - .header-title { font-size: 24px; font-weight: 700; margin-bottom: 0; + color: var(--text); } .header-subtitle { font-size: 13px; - opacity: 0.9; + color: var(--text-light); min-height: 20px; } @@ -98,9 +93,9 @@ body { .header-button { padding: 0.5rem 1rem; - background: rgba(255,255,255,0.2); - color: white; - border: 1px solid rgba(255,255,255,0.4); + background: var(--bg); + color: var(--primary); + border: 1px solid var(--border); border-radius: 6px; cursor: pointer; font-size: 13px; @@ -109,12 +104,14 @@ body { } .header-button:hover { - background: rgba(255,255,255,0.3); - border-color: white; + background: var(--primary-light); + border-color: var(--primary); } .step-counter { - background: rgba(255,255,255,0.2); + background: var(--bg); + border: 1px solid var(--border); + color: var(--text-light); padding: 0.4rem 0.8rem; border-radius: 20px; font-size: 12px; @@ -397,6 +394,71 @@ body { .comments-toggle:hover { background: var(--primary); color: white; } +/* CONSTRUCTION SEQUENCE (drag & drop) */ +#sequence-list { display: flex; flex-direction: column; gap: 8px; } +.seq-step { + display: flex; align-items: center; gap: 12px; padding: 11px 14px; + background: var(--bg-card); border: 1px solid var(--border); border-radius: 6px; + box-shadow: var(--shadow); transition: border-color .12s, box-shadow .12s, opacity .12s; +} +.seq-step:hover { border-color: var(--primary); } +.seq-step.dragging { opacity: .35; border-style: dashed; } +.seq-step.drag-over { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-light); } +.seq-handle { cursor: grab; color: var(--text-dim); font-size: 16px; line-height: 1; user-select: none; flex-shrink: 0; } +.seq-handle:active { cursor: grabbing; } +.seq-num { + width: 24px; height: 24px; flex-shrink: 0; border-radius: 50%; background: var(--primary-light); color: var(--primary); + font-size: 11px; font-weight: 600; display: flex; align-items: center; justify-content: center; +} +.seq-step input.seq-label { + border: 1px solid transparent; background: transparent; font-size: 14px; padding: 5px 8px; color: var(--text); flex: 1; border-radius: 4px; +} +.seq-step input.seq-label:focus { background: var(--bg); border-color: var(--primary); outline: none; } +.seq-del { + background: var(--danger); color: white; border: none; border-radius: 4px; + width: 28px; height: 28px; cursor: pointer; font-weight: 600; flex-shrink: 0; +} +.seq-arrow { text-align: center; color: var(--text-dim); font-size: 13px; line-height: .4; margin: -2px 0; } +.seq-step.gate { border-color: var(--warning); background: #fff7ed; border-style: dashed; } +.seq-step.gate .seq-label { color: var(--warning); font-weight: 500; } +.seq-gate-badge { + flex-shrink: 0; padding: 3px 9px; border-radius: 20px; background: var(--warning); color: #fff; + font-size: 9px; font-weight: 600; letter-spacing: .08em; white-space: nowrap; +} + +/* STEP COMMENTS DROPDOWN */ +.comments-dropdown { + position: fixed; + top: 80px; + right: 2rem; + width: 360px; + max-width: calc(100vw - 2rem); + background: var(--bg-card); + border: 1px solid var(--border); + border-radius: 8px; + box-shadow: var(--shadow-lg); + padding: 1.25rem; + z-index: 1200; +} + +.comments-dropdown-header { + display: flex; + justify-content: space-between; + align-items: center; + margin-bottom: 1rem; +} + +.comments-dropdown-close { + background: none; + border: none; + font-size: 16px; + cursor: pointer; + color: var(--text-light); + line-height: 1; +} + +.comments-dropdown-close:hover { color: var(--text); } + /* MODAL */ .modal { position: fixed; diff --git a/work-package-suite.html b/work-package-suite.html index c630860..8ff6637 100644 --- a/work-package-suite.html +++ b/work-package-suite.html @@ -14,13 +14,16 @@
-
Work Package Suite
-
+
+
Work Package Suite
+
+
+ + 1 / 10
@@ -97,7 +100,11 @@
- + +
+
+ +
@@ -108,6 +115,11 @@
+
+
Additional Team Members (optional)
+
+ +
@@ -230,9 +242,13 @@ @@ -260,24 +276,6 @@
- -
- - -
-
@@ -291,20 +289,38 @@
-
+ +

📋 Work Package Creation

-

Complete the SOP Configuration first to enable Work Package creation.

-
-

SOP Status: Not started

-

-
+

Complete the SOP Configuration first to enable Work Package creation. Once the SOP is finished, the full creator loads here with your project defaults pre-populated.

+
+ +
+ + +