Four affordances under three names became ONE: "Load sample data", on the creator's toolbar, at the far end of two separators from the live actions (New / Duplicate), pushed right with its own gap. It confirms through the T7.9 dialog, naming exactly what it does - and what it does not: "This page only: nothing is written to the project unless you then save." The probe verifies the fence the way the done-when demands - against a REAL project, reading the server's SOP and work-package list before and after and asserting byte-identical. Gone: the wizard's header "Load sample" (the dangerous one: it filled the state completeSOP() pushes to the LIVE project, one click, no confirm, no undo - reconciled with D1 exactly as the task records: the creator's control is the survivor, the wizard copy goes), the creator's split Sample SOP / Load example pair (now internals behind the one entry point), and the empty-state context bar's third button (its text now points at the toolbar control). The location/material "Load sample values" buttons stay: they fill a PASTE BOX that acts only through an explicit, dry-runnable import - a different thing, stated in the code. Probes re-pointed with reasons in place: frame_check's D1 toolbar list names the consolidated control; validation_check's sample-driven toast checks became the-affordance-is-gone checks (and its stale showAnalytics drive, orphaned by T7.10, became a the-duplicate-stays-gone check). Verification (each probe run alone): NEW tests/sample_check.py 10/10. Regressions: validation_check 77/77, frame_check 38/38, kitting_check 26/26, export_check 20/20, sections_check 95/95. Items: S7 (D1 reconciliation honored) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
619 lines
41 KiB
HTML
619 lines
41 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||
<title>Work Package Suite</title>
|
||
<script src="auth-guard.js"></script>
|
||
<!-- Date/number formatting. Must parse BEFORE the app scripts: they format
|
||
timestamps during their own boot. -->
|
||
<script src="wp-format.js"></script>
|
||
<!-- Addressable state (S3). Parses before the app scripts, which read the URL
|
||
during their own boot. -->
|
||
<script src="wp-url.js"></script>
|
||
<script src="wp-usage.js"></script>
|
||
<script src="wp-list-import.js"></script>
|
||
<!-- Autosave, unsaved-work guard, draft recovery (S2). -->
|
||
<script src="wp-autosave.js"></script>
|
||
<!-- Which work package sections this project uses (CR-006). Shared with the
|
||
creator so the two cannot disagree about what "Assets is off" means. -->
|
||
<script src="wp-sections.js"></script>
|
||
<link rel="icon" href="favicon.ico" sizes="any">
|
||
<link rel="manifest" href="manifest.webmanifest">
|
||
<meta name="theme-color" content="#161616">
|
||
<link rel="stylesheet" href="theme-light.css">
|
||
<link rel="stylesheet" href="wp-chrome.css">
|
||
<link rel="stylesheet" href="wp-sidenav.css">
|
||
<link rel="stylesheet" href="work-package-suite-styles.css">
|
||
</head>
|
||
<body>
|
||
<div class="app-container">
|
||
<!-- HEADER -->
|
||
<div class="header">
|
||
<div class="header-left">
|
||
<a href="index.html" class="logo" title="Back to Home">
|
||
<img src="prime-controls-logo.jpg" alt="Prime Controls" style="height: 24px; width: auto;">
|
||
</a>
|
||
<div style="min-width:0;overflow:hidden">
|
||
<div class="header-title">Work Package Suite</div>
|
||
<div class="header-subtitle" id="project-display"></div>
|
||
</div>
|
||
</div>
|
||
<div class="header-right">
|
||
<button class="header-button" onclick="toggleComments()" title="Leave feedback for the current step">Feedback</button>
|
||
<button class="header-button" onclick="openHelp()" title="How the suite works + key concepts">Help</button>
|
||
<!-- A4/S9: the orphaned "1 / 10" counter lived here. It is retired — the
|
||
step rail below says where you are, what is done and what is not
|
||
reachable yet, which is the job the counter was standing in for. -->
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MAIN NAVIGATION (B7 / T7.1)
|
||
Two of these three tabs used to swap an iframe. The creator is its own
|
||
document now, so they are links - real ones, so middle-click and
|
||
ctrl-click work and the browser's own back button is the back button.
|
||
wp-chrome.js stamps ?project= onto each once the active project is known.
|
||
|
||
They are still gated: until the SOP is complete there is nothing for the
|
||
creator to build from, and clicking one opens the gate panel instead of
|
||
navigating. A gated tab keeps its focus and says why, rather than
|
||
disappearing - see switchTool() in work-package-suite-app.js. -->
|
||
<div class="main-nav" role="navigation" aria-label="Work package tools">
|
||
<button class="nav-tab active" data-tab="sop" onclick="switchTool('sop')">
|
||
SOP Configuration
|
||
</button>
|
||
<a class="nav-tab" data-tab="wp" data-nav-href="wp-creation-index.html"
|
||
onclick="return gateCreatorLink(event)">
|
||
Work Package Creation
|
||
</a>
|
||
<a class="nav-tab" data-tab="dashboard" data-nav-href="wp-creation-index.html?view=dashboard"
|
||
onclick="return gateCreatorLink(event)">
|
||
Dashboard
|
||
</a>
|
||
</div>
|
||
|
||
<!-- CONTENT AREA -->
|
||
<div class="content-area">
|
||
|
||
<!-- ═════════════════════════════════════════════════════════════════════ -->
|
||
<!-- SOP CONFIGURATION TOOL -->
|
||
<!-- ═════════════════════════════════════════════════════════════════════ -->
|
||
<div id="tool-sop" class="tool active">
|
||
|
||
<!-- SOP STEP RAIL — A4 / S9 / C1
|
||
Was ten div elements carrying onclick, in a horizontally scrolling
|
||
strip: not in the tab order, not operable by keyboard, and silent
|
||
about which steps were finished or reachable. (Spelled out rather
|
||
than quoted, because the wave 0 baseline counts that markup with a
|
||
grep and a comment about it would inflate the number it is proving
|
||
went down.) Every step is a real button now, the
|
||
states are rendered by renderStepRail() in work-package-suite-app.js,
|
||
and each state carries a word as well as a colour.
|
||
|
||
The list is static markup rather than JS-built so the rail exists
|
||
before any script runs — a step you cannot see is a step you cannot
|
||
reach, and the wizard's scripts are render-blocking classics. -->
|
||
<nav class="step-rail is-collapsed" id="step-rail" aria-label="SOP configuration steps">
|
||
<!-- Narrow widths only (see the 899px breakpoint). Ten vertical rows
|
||
above the form is most of a 390px screen, so the rail collapses to
|
||
where-you-are and opens on demand. -->
|
||
<button type="button" class="step-rail-toggle" id="step-rail-toggle"
|
||
aria-expanded="false" aria-controls="step-rail-list">
|
||
<span class="step-rail-toggle-text">Step <span id="step-rail-pos">1</span> of <span id="step-rail-total">12</span> · <span id="step-rail-here">Project</span></span>
|
||
<span class="step-rail-toggle-chev" aria-hidden="true">▾</span>
|
||
</button>
|
||
<ol class="step-rail-list" id="step-rail-list">
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="1"><span class="step-btn-marker" aria-hidden="true">1</span><span class="step-btn-body"><span class="step-btn-label">Project</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="2"><span class="step-btn-marker" aria-hidden="true">2</span><span class="step-btn-body"><span class="step-btn-label">Team</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="3"><span class="step-btn-marker" aria-hidden="true">3</span><span class="step-btn-body"><span class="step-btn-label">Sign-offs</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="4"><span class="step-btn-marker" aria-hidden="true">4</span><span class="step-btn-body"><span class="step-btn-label">WP types</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="5"><span class="step-btn-marker" aria-hidden="true">5</span><span class="step-btn-body"><span class="step-btn-label">Governance</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="6"><span class="step-btn-marker" aria-hidden="true">6</span><span class="step-btn-body"><span class="step-btn-label">Quality</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="7"><span class="step-btn-marker" aria-hidden="true">7</span><span class="step-btn-body"><span class="step-btn-label">Platforms</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="8"><span class="step-btn-marker" aria-hidden="true">8</span><span class="step-btn-body"><span class="step-btn-label">Sequence</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="9"><span class="step-btn-marker" aria-hidden="true">9</span><span class="step-btn-body"><span class="step-btn-label">Constraints</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="10"><span class="step-btn-marker" aria-hidden="true">10</span><span class="step-btn-body"><span class="step-btn-label">Sources</span><span class="step-btn-state"></span></span></button></li>
|
||
<!-- CR-005. Appended rather than inserted next to Project, which is where
|
||
it belongs by subject: renumbering steps 2-10 would touch every
|
||
sop-step-N id, every collectStepData case, every gate key and the
|
||
analytics history, for an ordering change. Numbers are cheap to
|
||
reorder once nothing depends on them; a renumbering buried in a
|
||
feature diff is not. -->
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="11"><span class="step-btn-marker" aria-hidden="true">11</span><span class="step-btn-body"><span class="step-btn-label">Locations</span><span class="step-btn-state"></span></span></button></li>
|
||
<li class="step-rail-item"><button type="button" class="step-btn" data-step="12"><span class="step-btn-marker" aria-hidden="true">12</span><span class="step-btn-body"><span class="step-btn-label">Sections</span><span class="step-btn-state"></span></span></button></li>
|
||
</ol>
|
||
<!-- Why a step you asked for did not open. role="alert" because a refused
|
||
navigation is an error and waiting for a pause to say so is too late
|
||
(S10 / T4.5). Empty until something is refused. -->
|
||
<p class="step-rail-msg" id="step-rail-msg" role="alert"></p>
|
||
</nav>
|
||
|
||
<!-- SOP STEP CONTENT -->
|
||
<div class="step-content">
|
||
|
||
<!-- STEP 1: PROJECT BASICS -->
|
||
<div class="step" id="sop-step-1" style="display: block;">
|
||
<h2>1. Project Basics</h2>
|
||
<div class="notice">Define the core project information that will be inherited by all Work Packages.</div>
|
||
<div class="field-grid">
|
||
<div class="field">
|
||
<label>Project name *</label>
|
||
<input type="text" id="proj_name" placeholder="e.g., Micron — INC Construction Work Packages" oninput="updateProjectDisplay()">
|
||
</div>
|
||
<div class="field">
|
||
<label>Project number *</label>
|
||
<input type="text" id="proj_number" placeholder="e.g., 26-67-008">
|
||
</div>
|
||
<div class="field">
|
||
<label>Client name *</label>
|
||
<input type="text" id="proj_client" placeholder="e.g., Micron Technology, Inc.">
|
||
</div>
|
||
<div class="field">
|
||
<label>Division / sector *</label>
|
||
<input type="text" id="proj_division" placeholder="e.g., Semiconductor, Oil & Gas, Data Center">
|
||
</div>
|
||
<div class="field">
|
||
<label>Site location *</label>
|
||
<input type="text" id="proj_site" placeholder="e.g., Boise, ID — Fab 7">
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 2: PROJECT TEAM -->
|
||
<div class="step" id="sop-step-2" style="display: none;">
|
||
<h2>2. Project Team Leadership</h2>
|
||
<div class="notice">Pick the key project leaders from the people assigned to this project. Choosing a
|
||
<strong>user account</strong> (rather than typing a name) is what lets the Work Package Creator offer them
|
||
as an owner and lets the suite email them — so add anyone missing to the project first, in the
|
||
<a href="admin.html" target="_blank" rel="noopener">Admin Console</a>.</div>
|
||
<div id="team-accounts-warn" class="notice" style="display:none; background:var(--warning-bg); color:var(--warning);"></div>
|
||
<div class="field-grid">
|
||
<div class="field">
|
||
<label>Project manager (PM)</label>
|
||
<select id="proj_pm" class="team-pick" data-team="pm"></select>
|
||
</div>
|
||
<div class="field">
|
||
<label>Assistant project manager (APM)</label>
|
||
<select id="proj_apm" class="team-pick" data-team="apm"></select>
|
||
</div>
|
||
<div class="field">
|
||
<label>Construction manager (CM)</label>
|
||
<select id="proj_cm" class="team-pick" data-team="cm"></select>
|
||
<div class="field-hint">Kept on the distribution list of every work package by default.</div>
|
||
</div>
|
||
<div class="field">
|
||
<label>Quality manager (QM)</label>
|
||
<select id="proj_qm" class="team-pick" data-team="qm"></select>
|
||
</div>
|
||
<div class="field">
|
||
<label>QA group — notified at Ready for QA</label>
|
||
<select id="proj_qagroup" multiple size="4" aria-describedby="qagroup-hint"></select>
|
||
<div class="field-hint" id="qagroup-hint">Everyone picked here is emailed when a work package reaches <strong>Ready for QA</strong> (CR-014). Hold Ctrl (Cmd on Mac) to pick several.</div>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top: 2rem; border-top: 1px solid var(--border); padding-top: 1.5rem;">
|
||
<div class="sub-heading">Additional Team Members (optional)</div>
|
||
<div id="team-members-list" style="margin-top: 1rem;"></div>
|
||
<button class="add-btn" onclick="addTeamMember()">+ Add team member</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 3: SIGN-OFF ROLES -->
|
||
<div class="step" id="sop-step-3" style="display: none;">
|
||
<h2>3. Required Sign-Off Roles</h2>
|
||
<div class="notice">Two roles are required on every package. They default to <strong>Superintendent</strong> and <strong>Foreman</strong> — rename either to fit your project (e.g. a BIM SOP uses <em>BIM Coordinator</em> and <em>Construction Lead</em>). Add more below.</div>
|
||
<div class="required-roles">
|
||
<div class="role-required">
|
||
<div class="role-checkbox">
|
||
<input type="checkbox" id="role_super" checked disabled>
|
||
<input type="text" id="role_super_title" value="Superintendent" title="Required role title" style="font-weight:600; padding:0.4rem 0.5rem; border:1px solid var(--border); border-radius:4px; min-width:180px;"><span style="color:var(--danger); margin-left:4px;">*</span>
|
||
</div>
|
||
<select id="role_super_name" class="user-pick" style="flex: 1; margin-left: 1rem;"></select>
|
||
</div>
|
||
<div class="role-required">
|
||
<div class="role-checkbox">
|
||
<input type="checkbox" id="role_foreman" checked disabled>
|
||
<input type="text" id="role_foreman_title" value="Foreman" title="Required role title" style="font-weight:600; padding:0.4rem 0.5rem; border:1px solid var(--border); border-radius:4px; min-width:180px;"><span style="color:var(--danger); margin-left:4px;">*</span>
|
||
</div>
|
||
<select id="role_foreman_name" class="user-pick" style="flex: 1; margin-left: 1rem;"></select>
|
||
</div>
|
||
</div>
|
||
<div style="margin-top: 2rem; border-top: 1px solid var(--border); padding-top: 1.5rem;">
|
||
<div class="sub-heading">Optional Additional Roles</div>
|
||
<div id="optional-roles-list" style="margin-top: 1rem;"></div>
|
||
<button class="add-btn" onclick="addOptionalRole()">+ Add role</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 4: WORK PACKAGE TYPES -->
|
||
<div class="step" id="sop-step-4" style="display: none;">
|
||
<h2>4. Work Package Types</h2>
|
||
<div class="notice">Enable the WP types your project will use. Add any special rules and the roles required to approve WO completion.
|
||
<strong>Spec Section</strong> is filled onto every work package of that type automatically, so nobody types it per package.</div>
|
||
<label id="bim-toggle-wrap" style="display:flex; align-items:flex-start; gap:0.6rem; padding:0.85rem 1rem; background:var(--bg); border:1px solid var(--border); border-radius:6px; margin:0 0 1rem; cursor:pointer;">
|
||
<input type="checkbox" id="bim_enabled" onchange="setBimEnabled(this.checked)" style="width:18px; height:18px; margin-top:2px; flex:none;">
|
||
<span><strong>Include BIM / VDC work packages on this project</strong><br>
|
||
<span style="color:var(--text-dim); font-size:12px;">adds model/engineering package types & release gates. in the creator each package is then tagged <strong>install (IWP)</strong> or <strong>BIM (EWP)</strong>, so the project can flow from BIM into construction. leave off for install-only projects.</span></span>
|
||
</label>
|
||
<!-- Shown instead of the toggle when an admin has the BIM tooling switched off app-wide. -->
|
||
<div id="bim-disabled-note" class="notice" style="display:none; background:var(--warning-bg); color:var(--warning);"></div>
|
||
<div id="wp-types-table" style="margin-top: 1.5rem;"></div>
|
||
</div>
|
||
|
||
<!-- STEP 5: GOVERNANCE -->
|
||
<div class="step" id="sop-step-5" style="display: none;">
|
||
<h2>5. Governance & WP Numbering</h2>
|
||
<div class="notice">Define how Work Packages are formatted, sized, and issued on this project. The choices here decide how the Work Package Creator behaves for every package.</div>
|
||
<div class="field-grid">
|
||
<div class="field">
|
||
<label>Work package number format *</label>
|
||
<input type="text" id="gov_woformat" placeholder="e.g., WP##-[Sector]-[TYPE]">
|
||
<small>Use ## for counter, [Sector] [TYPE] as variables</small>
|
||
</div>
|
||
<div class="field">
|
||
<label>Issuance strategy<span class="help-tip" data-tip="How Work Packages are grouped and released on this project. Pick one or more — most projects combine 'By Sector / Area' with 'By Phase / Sequence'.">i</span></label>
|
||
<select id="gov_issuance" multiple size="4">
|
||
<option selected>By Sector / Area</option>
|
||
<option>By Discipline</option>
|
||
<option>By Phase / Sequence</option>
|
||
<option>By Resource Availability</option>
|
||
</select>
|
||
<small>Hold Ctrl (Cmd on Mac) to select multiple.</small>
|
||
<div class="notice" style="margin-top:0.6rem; font-size:12px;">
|
||
<strong>Examples:</strong>
|
||
<ul style="margin:0.35rem 0 0; padding-left:1.1rem;">
|
||
<li><strong>By Sector / Area</strong> — one package per physical area, e.g. <em>all work in Sector 1P, Level 2 chase</em>.</li>
|
||
<li><strong>By Discipline</strong> — separate packages per trade, e.g. <em>Electrical wire-pull</em> vs <em>Mechanical install</em>.</li>
|
||
<li><strong>By Phase / Sequence</strong> — follow the build order, e.g. <em>rough-in → wire pull → terminations</em>.</li>
|
||
<li><strong>By Resource Availability</strong> — size to a crew/equipment window, e.g. <em>one boom-lift crew's week</em>.</li>
|
||
</ul>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style="margin:1.4rem 0 .4rem">How will Work Packages use disciplines?</h3>
|
||
<div class="notice">Decide whether a single package can carry more than one discipline (e.g. a chiller skid needing Mechanical install + Electrical wire-pull + Tech terminations), or whether each discipline gets its own package. This drives whether the Creator shows per-discipline scope sections and the <strong>Split by Discipline</strong> button.</div>
|
||
<div class="field-grid">
|
||
<div class="field">
|
||
<label>Disciplines on this project</label>
|
||
<input type="text" id="gov_disciplines" placeholder="Mechanical, Electrical, Tech">
|
||
<small>Comma-separated. These appear as scope sections and instance suffixes in the Creator.</small>
|
||
</div>
|
||
<div class="field">
|
||
<label>Discipline strategy *<span class="help-tip" data-tip="Decides whether a package can carry several disciplines (scope split per discipline) or one each. 'Let the planner choose' allows building a big multi-discipline package and splitting it later.">i</span></label>
|
||
<select id="gov_discmode">
|
||
<option value="choice">Let the planner choose per package (recommended)</option>
|
||
<option value="single">One discipline per package (many small packages)</option>
|
||
<option value="multi">Multiple disciplines per package (scope split by discipline)</option>
|
||
</select>
|
||
<small>"Choose per package" lets the planner build a large multi-discipline package and split it later.</small>
|
||
</div>
|
||
</div>
|
||
|
||
<h3 style="margin:1.4rem 0 .4rem">Work Package sizing</h3>
|
||
<div class="notice">A Work Package should be a manageable, trackable chunk of work — typically a 1–2 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</label>
|
||
<select id="gov_wosize" onchange="onSizePresetChange()">
|
||
<option value="">Select…</option>
|
||
<option value="Small — 1–2 days (≈8–24 hrs)">Small — 1–2 days (≈8–24 hrs)</option>
|
||
<option value="Standard — 3–5 days (≈40–80 hrs)">Standard — 3–5 days (≈40–80 hrs)</option>
|
||
<option value="Large — 1–2 weeks (≈80–160 hrs)">Large — 1–2 weeks (≈80–160 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<span class="help-tip" data-tip="The Work Package Creator flags any package whose estimated hours exceed this so the planner can break it down. Auto-set by the size band; override if needed.">i</span></label>
|
||
<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>
|
||
|
||
<!-- STEP 6: QUALITY -->
|
||
<div class="step" id="sop-step-6" style="display: none;">
|
||
<h2>6. Quality & Inspection Strategy</h2>
|
||
<div class="notice">Establish project-wide quality expectations that cascade to every Work Package.</div>
|
||
<div class="field-grid col1">
|
||
<div class="field">
|
||
<label>QC required? *</label>
|
||
<select id="qual_qcreq">
|
||
<option>Yes</option>
|
||
<option>Yes — Detailed inspection items</option>
|
||
<option>Yes — Sample / Spot-check</option>
|
||
<option>No</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label>Photo / documentation standard</label>
|
||
<select id="qual_photo">
|
||
<option selected>Key checkpoints only</option>
|
||
<option>Every step documented</option>
|
||
<option>As-built final condition only</option>
|
||
<option>None</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label>Hold points & witness requirements</label>
|
||
<textarea id="qual_hold" rows="3" placeholder="e.g., HOLD: Prime QAQC to inspect rough-in before cover/cover-up. WITNESS: client QC to observe megger test before energization."></textarea>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 7: PLATFORMS -->
|
||
<div class="step" id="sop-step-7" style="display: none;">
|
||
<h2>7. Tracking & Commissioning Platforms</h2>
|
||
<div class="notice">Select the tools used for construction tracking and commissioning. These can be the same or different systems.</div>
|
||
<div class="field-grid">
|
||
<div class="field">
|
||
<label>Construction tracking platform *</label>
|
||
<select id="plat_tracking">
|
||
<option>CxAlloy</option>
|
||
<option>Procore</option>
|
||
<option>Autodesk Construction Cloud (ACC)</option>
|
||
<option>Other</option>
|
||
</select>
|
||
</div>
|
||
<div class="field">
|
||
<label>Commissioning tool *</label>
|
||
<select id="plat_commissioning">
|
||
<option selected>CxAlloy</option>
|
||
<option>Procore</option>
|
||
<option>Autodesk Construction Cloud (ACC)</option>
|
||
<option>Other</option>
|
||
</select>
|
||
</div>
|
||
</div>
|
||
<div class="field" style="margin-top:1rem;">
|
||
<label>Tracking platform — project homepage link</label>
|
||
<input type="url" id="plat_tracking_url" placeholder="Paste the project's URL in the tracking platform (e.g. its Procore / CxAlloy project home)">
|
||
<small>Optional. Saved with every Work Package on this project for one-click access.</small>
|
||
</div>
|
||
<div class="field" style="margin-top:0.75rem;">
|
||
<label>Commissioning tool — project homepage link</label>
|
||
<input type="url" id="plat_commissioning_url" placeholder="Paste the project's URL in the commissioning tool">
|
||
<small>Optional. Saved with every Work Package on this project for one-click access.</small>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 8: SEQUENCE -->
|
||
<div class="step" id="sop-step-8" style="display: none;">
|
||
<h2>8. Construction Sequence</h2>
|
||
<div class="notice">Comes pre-sequenced with a typical install flow. Drag the ⠿ handle to reorder steps, edit labels inline, add a QC hold gate, or remove any step.</div>
|
||
<div id="sequence-list" style="margin-top: 1rem;"></div>
|
||
<div style="display:flex; gap:0.5rem; margin-top:1rem; flex-wrap:wrap;">
|
||
<input type="text" id="seq-add-input" placeholder="New step name" onkeydown="if(event.key==='Enter'){addSequenceStep();}" style="flex:1; min-width:200px; padding:0.5rem; border:1px solid var(--border); border-radius:4px;">
|
||
<button class="add-btn" onclick="addSequenceStep()">+ Add step</button>
|
||
<button class="add-btn" onclick="addSequenceGate()" style="background:var(--warning);">Add QC hold</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 9: CONSTRAINTS -->
|
||
<div class="step" id="sop-step-9" style="display: none;">
|
||
<h2>9. Release Gate Constraints</h2>
|
||
<div class="notice">Constraints are readiness items that must be cleared before a WP can be issued.</div>
|
||
<div style="margin-bottom: 2rem;">
|
||
<div class="sub-heading">Standard AWP Constraints (Vol II §2.3.2)</div>
|
||
<div id="standard-constraints" style="margin-top: 1rem;"></div>
|
||
</div>
|
||
<div style="border-top: 1px solid var(--border); padding-top: 1.5rem;">
|
||
<div class="sub-heading">Custom Constraints (Optional)</div>
|
||
<div id="custom-constraints-list" style="margin-top: 1rem;"></div>
|
||
<button class="add-btn" onclick="showConstraintLibrary()">+ Add custom constraint</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 10: SOURCES -->
|
||
<div class="step" id="sop-step-10" style="display: none;">
|
||
<h2>10. Engineering Sources & References</h2>
|
||
<div class="notice">Link to key documents and systems that WP authors will reference.</div>
|
||
<div id="sources-list" style="margin-top: 1rem;"></div>
|
||
<button class="add-btn" onclick="addSource()">+ Add source</button>
|
||
</div>
|
||
|
||
<!-- STEP 11: LOCATIONS (CR-005)
|
||
Server-backed, not localStorage: CR-018 rolls cost up by these
|
||
values, and a taxonomy each browser keeps its own copy of cannot
|
||
be rolled up by anything. See CLAUDE.md, "Frontend and backend
|
||
boundary". -->
|
||
<div class="step" id="sop-step-11" style="display: none;">
|
||
<h2>11. Location List</h2>
|
||
<div class="notice">Building, floor and sector for this project. The shape of a
|
||
location differs per job — on some, floors within one building behave like
|
||
separate buildings and are the unit of both execution and cost tracking — so it
|
||
is configured here rather than assumed. Work packages pick from this list, and
|
||
cost rolls up by it.</div>
|
||
|
||
<div id="loc-noproject" class="notice" style="display:none; background:var(--warning-bg); color:var(--warning);"></div>
|
||
|
||
<div id="loc-tool">
|
||
<div class="field-grid col1">
|
||
<div class="field">
|
||
<label for="loc-paste">Paste rows, or upload a CSV</label>
|
||
<textarea id="loc-paste" rows="6" aria-describedby="loc-paste-hint"
|
||
placeholder="One row per sector, e.g. Building, Floor, Sector"></textarea>
|
||
<small id="loc-paste-hint">One row per value, deepest level last:
|
||
<strong>building, floor, sector</strong>. Two columns describe a floor,
|
||
one describes a building. Comma, semicolon or tab separated — a paste
|
||
straight out of a spreadsheet works. A header row is ignored.</small>
|
||
</div>
|
||
</div>
|
||
<div class="loc-actions">
|
||
<input type="file" id="loc-file" accept=".csv,.txt,text/csv,text/plain" hidden>
|
||
<button type="button" class="add-btn" id="loc-file-btn">Choose a CSV file…</button>
|
||
<button type="button" class="add-btn" id="loc-check-btn">Check without importing</button>
|
||
<button type="button" class="add-btn" id="loc-import-btn">Import</button>
|
||
<button type="button" class="add-btn" id="loc-sample-btn">Load sample values</button>
|
||
</div>
|
||
<!-- Rejected rows and duplicates land here, with line numbers. An
|
||
import that says "42 rows" over a file with 50 in it has lost
|
||
eight and told nobody, which is what this exists to prevent. -->
|
||
<div class="loc-report" id="loc-report" role="status"></div>
|
||
|
||
<div style="margin-top: 2rem; border-top: 1px solid var(--border); padding-top: 1.5rem;">
|
||
<div class="sub-heading">Current list</div>
|
||
<p class="field-hint" id="loc-count"></p>
|
||
<div id="loc-list"></div>
|
||
<div class="loc-addrow">
|
||
<label class="loc-addlabel" for="loc-add-parent">Add under</label>
|
||
<select id="loc-add-parent"></select>
|
||
<label class="loc-addlabel" for="loc-add-name">Name</label>
|
||
<input type="text" id="loc-add-name" placeholder="e.g. a new sector">
|
||
<button type="button" class="add-btn" id="loc-add-btn">+ Add</button>
|
||
</div>
|
||
<div class="field-error" id="loc-add-err" role="alert"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MATERIAL LIST (D6 / T8.6). Same component as the location list
|
||
above (wp-list-import.js), same rules: paste or file, dry-run
|
||
check, rejected rows named by source line, deactivate not
|
||
delete. Description, unit, optional code - and nothing else:
|
||
no inventory, no pricing, no warehouse id. -->
|
||
<div style="margin-top: 2.5rem; border-top: 1px solid var(--border); padding-top: 1.5rem;">
|
||
<div class="sub-heading">Material list (D6)</div>
|
||
<div class="step-desc">What a material request picks from (CR-013). Optional —
|
||
a project with no list still raises requests with free text.</div>
|
||
<div id="mat-noproject" class="notice" style="display:none; background:var(--warning-bg); color:var(--warning);"></div>
|
||
<div id="mat-tool">
|
||
<div class="field-grid col1">
|
||
<div class="field">
|
||
<label for="mat-paste">Paste rows, or upload a CSV</label>
|
||
<textarea id="mat-paste" rows="5" aria-describedby="mat-paste-hint"
|
||
placeholder="One row per material, e.g. Description, unit, code"></textarea>
|
||
<small id="mat-paste-hint">One row per material:
|
||
<strong>description, unit, code</strong> — unit and code optional.
|
||
Comma, semicolon or tab separated. A header row is ignored.</small>
|
||
</div>
|
||
</div>
|
||
<div class="loc-actions">
|
||
<input type="file" id="mat-file" accept=".csv,.txt,text/csv,text/plain" hidden>
|
||
<button type="button" class="add-btn" id="mat-file-btn">Choose a CSV file…</button>
|
||
<button type="button" class="add-btn" id="mat-check-btn">Check without importing</button>
|
||
<button type="button" class="add-btn" id="mat-import-btn">Import</button>
|
||
<button type="button" class="add-btn" id="mat-sample-btn">Load sample values</button>
|
||
</div>
|
||
<div class="loc-report" id="mat-report" role="status"></div>
|
||
<div style="margin-top: 1.5rem;">
|
||
<div class="sub-heading">Current list</div>
|
||
<p class="field-hint" id="mat-count"></p>
|
||
<div id="mat-list"></div>
|
||
<div class="loc-addrow">
|
||
<label class="loc-addlabel" for="mat-add-name">Description</label>
|
||
<input type="text" id="mat-add-name" placeholder="e.g. a strut channel">
|
||
<label class="loc-addlabel" for="mat-add-unit">Unit</label>
|
||
<input type="text" id="mat-add-unit" placeholder="EA / FT" style="max-width:90px">
|
||
<button type="button" class="add-btn" id="mat-add-btn">+ Add</button>
|
||
</div>
|
||
<div class="field-error" id="mat-add-err" role="alert"></div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- STEP 12: WORK PACKAGE SECTIONS (CR-006)
|
||
The structural fix behind most removal requests in the plan: rather
|
||
than deleting fields globally, each project turns on only the
|
||
sections it uses. CR-002 and CR-016 are expressed through these. -->
|
||
<div class="step" id="sop-step-12" style="display: none;">
|
||
<h2>12. Work Package Sections</h2>
|
||
<div class="notice">Turn off the parts of a work package this project does not
|
||
use. A section that is off does not appear in the creation form, in the work
|
||
package itself, or in the PDF export. <strong>Nothing is deleted.</strong>
|
||
Anything already captured stays on the package and comes back intact if the
|
||
section is turned on again — which is what makes this different from removing
|
||
a field.</div>
|
||
<div id="section-toggles"></div>
|
||
<p class="field-hint" id="section-summary" role="status"></p>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- SOP NAVIGATION -->
|
||
<div class="step-navigation">
|
||
<button class="nav-btn" id="sop-prev-btn" onclick="previousStep()">Back</button>
|
||
<button class="nav-btn" id="sop-next-btn" onclick="nextStep()">Next</button>
|
||
<button class="nav-btn primary" id="sop-complete-btn" onclick="completeSOP()" style="display: none;">SOP complete</button>
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- ═════════════════════════════════════════════════════════════════════ -->
|
||
<!-- WORK PACKAGE CREATION TOOL -->
|
||
<!-- ═════════════════════════════════════════════════════════════════════ -->
|
||
<div id="tool-wp" class="tool">
|
||
<!-- Shown until the SOP is complete -->
|
||
<div id="wp-gate" style="padding: 3rem 2rem; text-align: center;">
|
||
<h2>Work Package Creation</h2>
|
||
<p style="color: var(--text-light); margin: 1rem 0;">Complete the SOP Configuration first to enable Work Package creation. Once the SOP is finished, the Work Package Creation tab opens the creator with your project defaults pre-populated.</p>
|
||
<button class="nav-btn primary" onclick="switchTool('sop')" style="margin-top: 1rem;">Go to SOP configuration</button>
|
||
</div>
|
||
<!-- B7/T7.1: the iframe stood here. The creator is a page now
|
||
(wp-creation-index.html), reached through the tab above, so this tab
|
||
holds only the gate: the state where there is no SOP to build from.
|
||
Once there is one, the tab navigates and this panel is never seen. -->
|
||
</div>
|
||
|
||
</div>
|
||
|
||
</div>
|
||
|
||
<!-- STEP COMMENTS DROPDOWN (toggled from header) -->
|
||
<div id="comments-panel" class="comments-dropdown" style="display: none;">
|
||
<div class="comments-dropdown-header">
|
||
<strong>Feedback</strong>
|
||
<button onclick="toggleComments()" class="comments-dropdown-close" title="Close">✕</button>
|
||
</div>
|
||
<div style="margin-bottom: 1rem;">
|
||
<label style="font-weight: 600; font-size: 13px;">Your name</label>
|
||
<input type="text" id="commenter-name" placeholder="(signed-in user)" readonly title="Taken from your sign-in" style="width: 100%; padding: 0.5rem; border: 1px solid var(--border); border-radius: 4px; margin-top: 0.25rem; background: var(--bg);">
|
||
</div>
|
||
<div style="margin-bottom: 1rem;">
|
||
<label style="font-weight: 600; font-size: 13px;" for="comment-text">Feedback</label>
|
||
<textarea id="comment-text" rows="3" placeholder="Your feedback here..." aria-describedby="comment-text_err" style="width: 100%; padding: 0.5rem; border: 1px solid var(--border); border-radius: 4px; margin-top: 0.25rem; font-family: inherit;"></textarea>
|
||
<div class="field-error" id="comment-text_err" role="alert"></div>
|
||
</div>
|
||
<div style="display:flex; gap:0.5rem; flex-wrap:wrap;">
|
||
<button onclick="submitComment()" style="background: var(--primary); color: var(--cds-text-on-color); padding: 0.5rem 1rem; border: none; border-radius: 4px; cursor: pointer; font-weight: 600;">Submit</button>
|
||
<button onclick="exportComments()" style="background: var(--bg); color: var(--text); border: 1px solid var(--border); padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: 600;">Export</button>
|
||
<button onclick="document.getElementById('sop-comments-import').click()" style="background: var(--bg); color: var(--text); border: 1px solid var(--border); padding: 0.5rem 1rem; border-radius: 4px; cursor: pointer; font-weight: 600;">Import</button>
|
||
<input type="file" id="sop-comments-import" accept="application/json" style="display:none" onchange="importComments(event)">
|
||
</div>
|
||
<div id="comments-list" style="margin-top: 1rem; max-height: 240px; overflow-y: auto;"></div>
|
||
</div>
|
||
|
||
<!-- CONSTRAINT LIBRARY MODAL -->
|
||
<div id="constraint-modal" class="modal" style="display: none;">
|
||
<div class="modal-content">
|
||
<div class="modal-header">
|
||
<h3>Add Custom Constraint</h3>
|
||
<button class="modal-close" onclick="closeConstraintModal()">✕</button>
|
||
</div>
|
||
<div style="display:flex; gap:0.5rem; margin:1rem 0 0.5rem;">
|
||
<input type="text" id="custom-constraint-input" placeholder="Type a custom constraint name…" style="flex:1; padding:0.55rem 0.65rem; border:1px solid var(--border); border-radius:4px;" onkeydown="if(event.key==='Enter'){addCustomConstraintText();event.preventDefault();}">
|
||
<button class="add-btn" onclick="addCustomConstraintText()">Add</button>
|
||
</div>
|
||
<div style="font-size:12px; color:var(--text-dim); margin-bottom:0.5rem;">…or pick from the library:</div>
|
||
<div id="constraint-library" style="max-height: 320px; overflow-y: auto; margin: 0 0 1rem;"></div>
|
||
<button class="nav-btn" onclick="closeConstraintModal()">Done</button>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- S1 / T5.8. Every message the wizard used to put in a native dialog lands
|
||
here instead. role is set per message: an error interrupts, a confirmation
|
||
does not (T4.5). A dialog cannot be styled, cannot be read by a screen
|
||
reader as anything but a modal interruption, and — the reason this matters
|
||
beyond taste — blocks the page until it is dismissed. -->
|
||
<div id="wp-toast" class="wp-toast" role="status" hidden></div>
|
||
|
||
<script src="feedback-config.js"></script>
|
||
<script src="project-data.js"></script>
|
||
<script src="help.js"></script>
|
||
<script src="work-package-suite-app.js"></script>
|
||
<script src="wp-chrome.js"></script>
|
||
<script src="wp-sidenav.js"></script>
|
||
</body>
|
||
</html>
|