Site comments (8/3) - BIM card: LOD removed, IFF # added next to the coordination status, and required once that status is "Signed off (IFF)" — an unnumbered sign-off isn't traceable. A LOD already stored on a package is preserved and shown as legacy, not blanked. - The blue "from SOP types" subtext under a field is now a SOP chip on the label with the detail in a tooltip. The chip stays visible rather than hover-only: field tablets have no hover, and "this came from the SOP" is the part that matters. The hint elements stay in the DOM (hidden) so the code writing to them keeps working; an observer mirrors their text into the tooltip. - Specification Section is no longer typed per package. Each WP type carries a spec section on the SOP; the field is read-only in the Creator and follows the type, with the SOP's spec folder linked underneath. This reads both spec comments as one intent — stop typing it, derive it. - Assignees and Distribution are multi-selects over the SOP project team, showing each person's job function, with the CM pre-added to Distribution (removable per package) and a free-text option for people with no account. The stored display strings are unchanged so print/export/dashboard keep working; account ids ride alongside for the notification work in wave 3. Localization + time - Per-user locale/timezone (Language & time in the user menu), an app-wide default in the admin console, then the browser. Timezones are validated against the server's zoneinfo and the picker is fed from it. Calendar dates are formatted from their parts so a due date never reads a day early in another zone. - Every displayed timestamp now goes through the shared helpers. Top-bar chrome - Project switcher beside the logo and a centered global search, injected into either generation of top bar; skipped in an iframe so the embedded Creator doesn't get a second one. Ctrl/Cmd-K focuses search. - GET /api/search covers work packages, projects and SOPs, scoped to the caller's projects, hiding archived packages, with LIKE wildcards escaped. Fixed along the way: showForm() cleared every card's inline display, which undid applyKind() — so the Package Type and BIM cards reappeared on an install-only project. Split out applyKindVisibility() and re-apply it there. Verified: 100 API checks on a fresh database (44 permissions + 22 password reset + 34 search/localization), 24 driven UI checks against the real Creator page in headless Chrome (SOP chips, both people pickers, spec auto-fill, critical tags, BIM suppression), and the chrome harness on both bar styles. Screenshots reviewed. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
353 lines
26 KiB
HTML
353 lines
26 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="en">
|
||
<head>
|
||
<meta charset="UTF-8">
|
||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||
<title>Work Package (IWP) — Prime Controls</title>
|
||
<script src="auth-guard.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-creation-styles.css">
|
||
</head>
|
||
<body>
|
||
|
||
<div class="loading-overlay" id="loadingOverlay"><div class="spinner"></div><div class="loading-text">Saving work package…</div></div>
|
||
|
||
<div class="header">
|
||
<div class="logo-wrap embed-hide">
|
||
<div class="header-logo">Prime Controls</div>
|
||
<button id="dev-toggle" class="dev-toggle" onclick="toggleDevMode()" title="dev mode" aria-label="dev mode"></button>
|
||
</div>
|
||
<div class="header-sep embed-hide">|</div>
|
||
<div class="header-title">Work Package (IWP)</div>
|
||
<button class="btn btn-ghost embed-hide" style="margin-left:auto;padding:7px 16px" onclick="document.getElementById('sop-import').click()">⤒ Import SOP</button>
|
||
<input type="file" id="sop-import" accept="application/json" style="display:none" onchange="importSOP(event)">
|
||
<button class="btn btn-ghost embed-hide" style="padding:7px 16px" onclick="loadSampleSOP()">⤓ Sample SOP</button>
|
||
<button class="btn btn-ghost embed-hide" style="padding:7px 16px" onclick="openSopModal()">👁 View SOP</button>
|
||
<button class="btn btn-ghost embed-hide" style="padding:7px 16px" onclick="loadExample()">★ Load Example</button>
|
||
<button class="btn btn-ghost embed-hide" style="padding:7px 16px" onclick="showDashboard()">📊 Dashboard</button>
|
||
<button class="btn btn-ghost embed-first" style="padding:7px 16px" onclick="newPackage()">+ New</button>
|
||
<button class="btn btn-ghost" style="padding:7px 16px" onclick="duplicateWP()">⧉ Duplicate</button>
|
||
<button class="btn btn-ghost" style="padding:7px 16px" onclick="showHistoryCurrent()" title="Change history for this work package">🕘 History</button>
|
||
<button class="btn btn-ghost embed-hide" id="comments-btn" style="padding:7px 16px" onclick="toggleComments()">💬 Comments <span class="cbadge-total" id="cbadge-total" style="display:none">0</span></button>
|
||
<button class="btn btn-ghost embed-hide" style="padding:7px 16px" onclick="showAnalytics()">▤ Usage Data</button>
|
||
</div>
|
||
|
||
<div class="dev-banner" id="dev-banner" style="display:none">⚙ DEV MODE — usage tracking paused. This session's actions are not being recorded.</div>
|
||
|
||
<div class="ctx-bar" id="ctx-bar"></div>
|
||
|
||
<!-- RELEASE READINESS BANNER -->
|
||
<div class="release-banner" id="release-banner"></div>
|
||
|
||
<!-- SECTION NAV (jump links, built from the form cards) -->
|
||
<div class="section-nav-bar" id="section-nav"></div>
|
||
|
||
<div class="wp-layout">
|
||
|
||
<!-- WP NAVIGATOR (left rail — jump between every work package on this project) -->
|
||
<aside class="wp-nav" id="wp-nav" aria-label="Work packages">
|
||
<div class="wp-nav-head">
|
||
<div class="wp-nav-title">Work Packages <span class="wp-nav-count" id="wp-nav-count"></span></div>
|
||
<button class="wp-nav-collapse" id="wp-nav-collapse" onclick="toggleWpNav()" title="Collapse list" aria-label="Collapse list">‹</button>
|
||
</div>
|
||
<input type="search" class="wp-nav-search" id="wp-nav-search" placeholder="Filter by number, subject, type…" oninput="renderWpNav()">
|
||
<div class="wp-nav-list" id="wp-nav-list"></div>
|
||
<div class="wp-nav-foot">
|
||
<button class="add-btn" onclick="newPackage()">+ New</button>
|
||
<button class="add-btn" onclick="showDashboard()">📊 Dashboard</button>
|
||
</div>
|
||
</aside>
|
||
<button class="wp-nav-reopen" id="wp-nav-reopen" onclick="toggleWpNav()" title="Show work packages" aria-label="Show work packages">›</button>
|
||
|
||
<div class="main">
|
||
|
||
<!-- PACKAGE KIND (only shown when the project's SOP includes BIM/VDC) -->
|
||
<div class="card" id="kind-row" style="display:none">
|
||
<div class="sub-heading">Package Type</div>
|
||
<div class="notice">This project includes BIM/VDC packages. Choose what this one is — it tailors the fields below and the WP types / release gates offered.</div>
|
||
<div class="radio-group" id="kind-group" style="margin-bottom:0">
|
||
<label class="radio-pill" data-val="iwp"><input type="radio" name="pkgkind" onclick="setKind('iwp')"><span class="dot"></span>Install package (IWP)</label>
|
||
<label class="radio-pill" data-val="ewp"><input type="radio" name="pkgkind" onclick="setKind('ewp')"><span class="dot"></span>BIM package (EWP)</label>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- GENERAL INFORMATION -->
|
||
<div class="card">
|
||
<div class="section-header"><div class="section-title">General Information</div>
|
||
<div class="section-desc">Parameters in <span style="color:var(--accent)">blue</span> are inherited from the project SOP. Fill the rest for this package.</div></div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>WP Number <span class="auto-tag">auto</span><span class="help-tip" data-tip="Built automatically from the SOP number format — the scope fields below (e.g. Sector) plus the WP type and a sequence counter.">i</span></label><input type="text" id="wp_number" readonly class="locked-field" placeholder="auto-built"><div class="field-hint sop-hint" id="wp_number_hint"></div></div>
|
||
<div class="field"><label>Status</label>
|
||
<div class="radio-group" id="status-group" style="margin-bottom:0">
|
||
<label class="radio-pill" data-val="Draft"><input type="radio" name="status"><span class="dot"></span>Draft</label>
|
||
<label class="radio-pill" data-val="Scheduled"><input type="radio" name="status"><span class="dot"></span>Scheduled</label>
|
||
<label class="radio-pill" data-val="Issued"><input type="radio" name="status"><span class="dot"></span>Issued</label>
|
||
<label class="radio-pill" data-val="In Progress"><input type="radio" name="status"><span class="dot"></span>In Progress</label>
|
||
<label class="radio-pill pill-hold" data-val="Issue"><input type="radio" name="status"><span class="dot"></span>Issue (Hold)</label>
|
||
<label class="radio-pill" data-val="QC"><input type="radio" name="status"><span class="dot"></span>QC</label>
|
||
<label class="radio-pill" data-val="Closed"><input type="radio" name="status"><span class="dot"></span>Closed</label>
|
||
</div>
|
||
<div class="field-hint">Cannot move to <strong>Issued</strong> or beyond until all constraints are cleared.</div>
|
||
</div>
|
||
</div>
|
||
<div class="notice">WP number builds automatically from these scope fields + the WP type (per the SOP naming format):</div>
|
||
<div class="field-grid" id="number-dims"></div>
|
||
<div class="field field-grid col1"><div class="field"><label>Subject / Title <span class="req">*</span></label><input type="text" id="wp_subject" placeholder="e.g. Utility Level 2P Inert Gas Room Wall Mount Midas/ Rack"></div></div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>WP Type <span class="req">*</span></label><select id="wp_type" onchange="onTypeChange()"></select><div class="field-hint sop-hint">from SOP types</div></div>
|
||
<div class="field"><label>System / Facility Code / UPN</label><input type="text" id="wp_system" placeholder="ties to controls.dev / COIN"></div>
|
||
<div class="field"><label>Location</label><input type="text" id="wp_location" placeholder="building / level / sector / room"></div>
|
||
<div class="field"><label>Cost Code</label><select id="wp_cost"></select><div class="field-hint sop-hint">Acumatica cost codes</div></div>
|
||
<div class="field"><label>Acumatica Task</label><input type="text" id="wp_wbs" placeholder="Acumatica task no."></div>
|
||
</div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>Owner <span class="help-tip" data-tip="The accountable owner (a user account on this project). Assigning notifies them by email if email notifications are enabled in the admin console.">i</span></label><select id="wp_assignee"><option value="">— Unassigned —</option></select></div>
|
||
<div class="field"><label>Assignees<span class="help-tip" data-tip="The crew and staff working this package. Pick from the project team named on the SOP; anyone without a user account can still be added by name.">i</span></label>
|
||
<div class="people-pick" id="pick_assignees"></div>
|
||
<input type="hidden" id="wp_assignees"></div>
|
||
<div class="field"><label>Distribution<span class="help-tip" data-tip="Who gets notified about this package. The project's Construction Manager is included by default and can be removed per package.">i</span></label>
|
||
<div class="people-pick" id="pick_distribution"></div>
|
||
<input type="hidden" id="wp_distribution"></div>
|
||
<div class="field"><label>Due Date</label><input type="date" id="wp_due"></div>
|
||
<div class="field"><label>Specification Section</label>
|
||
<input type="text" id="wp_spec" readonly class="locked-field" placeholder="set on the WP type in the SOP">
|
||
<div class="field-hint" id="spec-folder-link"></div></div>
|
||
</div>
|
||
<div class="field field-grid col1"><div class="field"><label>Description</label><textarea id="wp_desc" rows="2" placeholder="Short summary of the package"></textarea></div></div>
|
||
<div class="field field-grid col1" id="bimlink-wrap"><div class="field"><label>Enabled by — BIM package(s)<span class="help-tip" data-tip="Advanced Work Packaging traceability: link the BIM / model package(s) that enabled this install package. Paste the MWP number(s) or a link to the model package.">i</span></label><input type="text" id="wp_bimlink" placeholder="e.g. MWP07-FAB-CONDUITS, or a link to the model package"></div></div>
|
||
</div>
|
||
|
||
<!-- BIM / MODEL DETAILS (shown for BIM/VDC SOPs) -->
|
||
<div class="card" id="bim-card" style="display:none">
|
||
<div class="sub-heading">BIM / Model Details</div>
|
||
<div class="notice">For BIM/VDC work packages — the model deliverable's level of detail, area, source scan, and coordination status.</div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>Model Area / Zone</label><input type="text" id="wp_model_area" placeholder="e.g. Fab 09 Subfab — Level 2"></div>
|
||
<div class="field"><label>Clash / Coordination Status</label>
|
||
<select id="wp_clash" onchange="onClashChange()"><option value="">—</option><option>Not started</option><option>In coordination</option><option>Clashes open</option><option>Clash-free</option><option>Signed off (IFF)</option></select></div>
|
||
<div class="field"><label>IFF #<span class="help-tip" data-tip="Issued-For-Fabrication/Field number — the GC sign-off reference for this model package. Required once the coordination status is Signed off (IFF).">i</span></label>
|
||
<input type="text" id="wp_iff" placeholder="e.g. IFF-2026-0142" oninput="onClashChange()">
|
||
<div class="field-hint" id="iff-hint"></div></div>
|
||
<div class="field"><label>Linked Scan / Point Cloud</label><input type="url" id="wp_scan_link" placeholder="WebShare / BIM360 / SharePoint link"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- ASSETS (controls.dev) -->
|
||
<div class="card" id="asset-card">
|
||
<div class="sub-heading">Assets</div>
|
||
<div class="notice">Every work package is based on one or more assets managed in <strong>controls.dev</strong>. Paste the controls.dev link for each asset this package covers. <span style="color:var(--text-dim)">A direct integration to pick assets from a list is planned — for now, link them manually.</span></div>
|
||
<div class="table-wrap"><table><thead><tr><th style="width:200px">Asset Tag / ID</th><th>Description</th><th>controls.dev Link <span class="req">*</span></th><th style="width:44px"></th></tr></thead><tbody id="asset-body"></tbody></table></div>
|
||
<button class="add-btn" onclick="addAsset()">+ Add Asset</button>
|
||
</div>
|
||
|
||
<!-- DISCIPLINES -->
|
||
<div class="card" id="discipline-card" style="display:none">
|
||
<div class="sub-heading">Disciplines<span class="help-tip" data-tip="Pick every discipline this package covers. Choosing two or more turns Scope into per-discipline sections and enables Split by Discipline.">i</span></div>
|
||
<div class="notice" id="discipline-note"></div>
|
||
<div class="disc-picker" id="discipline-picker"></div>
|
||
</div>
|
||
|
||
<!-- SCOPE & WORK -->
|
||
<div class="card">
|
||
<div class="sub-heading">Scope & Work<span class="help-tip" data-tip="Ordered steps the crew performs. With multiple disciplines selected, each gets its own scope section and status. Use Split by Discipline to break a large package into WP01A / WP01B / WP01C instances.">i</span></div>
|
||
<div id="flat-scope">
|
||
<div class="field"><label>Description of Work (sequenced steps)</label>
|
||
<div class="notice">Enter the work as ordered steps — added in sequence, the way the crew performs them.</div>
|
||
<div id="worksteps-body"></div>
|
||
<button class="add-btn" onclick="addWorkStep()">+ Add Step</button>
|
||
</div>
|
||
</div>
|
||
<div id="scope-by-discipline" style="display:none"></div>
|
||
<button class="btn btn-ghost" id="split-disc-btn" style="display:none;margin-top:10px" onclick="splitByDiscipline()" title="Break this multi-discipline package into one numbered instance per discipline">⎘ Split by Discipline</button>
|
||
<div class="field-grid" style="margin-top:14px">
|
||
<div class="field"><label>Labor – Est. Hrs.</label><input type="number" id="wp_hours" min="0" step="1" placeholder="e.g. 20" oninput="onHoursChange()"><div class="field-hint" id="size-check"></div></div>
|
||
<div class="field"><label>Package Predecessor</label><select id="wp_seq"></select><div class="field-hint">The package/step (from the SOP sequence) that must finish before this work can start. Choose "None" if it has no predecessor.</div></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- MATERIAL LIST -->
|
||
<div class="card" id="material-card">
|
||
<div class="sub-heading">Material List<span class="help-tip" data-tip="Bill of materials — feeds kitting. On a multi-discipline package each line can be tagged to a discipline so a split routes each instance only its own materials. Import from CSV is supported.">i</span></div>
|
||
<div class="notice">Structured bill of materials. Feeds kitting and the delivery forecast. Unit is from the Acumatica unit list.</div>
|
||
<div class="table-wrap"><table><thead><tr><th style="width:90px">Qty</th><th style="width:120px">Unit</th><th>Description</th><th id="mat-disc-th" style="width:140px;display:none">Discipline</th><th style="width:44px"></th></tr></thead><tbody id="material-body"></tbody></table></div>
|
||
<div class="material-actions">
|
||
<button class="add-btn" onclick="addMaterial()">+ Add Material Line</button>
|
||
<button class="add-btn" onclick="document.getElementById('material-import').click()">⤒ Import from Excel/CSV</button>
|
||
<button class="add-btn" onclick="downloadMaterialTemplate()">⤓ Download Template</button>
|
||
<input type="file" id="material-import" accept=".csv,.xlsx,.xls" style="display:none" onchange="importMaterials(event)">
|
||
</div>
|
||
</div>
|
||
|
||
<!-- DRAWINGS / ATTACHMENTS -->
|
||
<div class="card">
|
||
<div class="sub-heading">Drawings & Attachments</div>
|
||
<div id="sop-ref-links" class="sop-ref-links"></div>
|
||
<div class="table-wrap"><table><thead><tr><th>Document / Drawing</th><th style="width:90px">Rev</th><th>Link / Note</th><th style="width:44px"></th></tr></thead><tbody id="attach-body"></tbody></table></div>
|
||
<button class="add-btn" onclick="addAttach()">+ Add Document</button>
|
||
<button class="add-btn" onclick="toggleSopFilePanel()">+ Add files from SOP folder</button>
|
||
<div id="sop-file-panel" style="display:none; margin-top:0.75rem; padding:0.75rem; border:1px dashed var(--border); border-radius:6px; background:var(--bg);">
|
||
<div id="sop-file-folders"></div>
|
||
<div class="field-hint" style="margin-top:0.5rem;">2) Paste the file links here, one per line:</div>
|
||
<textarea id="sop-file-links" rows="4" placeholder="https://primecontrolsdallas.sharepoint.com/:b:/r/.../Drawings/EE-1YA-2P.pdf?csf=1&web=1&e=..." style="width:100%; font-size:12px; padding:0.5rem; border:1px solid var(--border); border-radius:4px; box-sizing:border-box;"></textarea>
|
||
<div style="margin-top:0.5rem; display:flex; gap:0.5rem;">
|
||
<button class="add-btn" onclick="addPastedFileLinks()">Add to attachments</button>
|
||
<button class="add-btn" onclick="toggleSopFilePanel()" style="background:transparent;">Cancel</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- KITTING & MIMO -->
|
||
<div class="card" id="mimo-card">
|
||
<div class="sub-heading">Kitting & Material Movement (MIMO)</div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>Kitting Status</label>
|
||
<select id="wp_kit_status"><option value="">—</option><option>Open</option><option>In Progress</option><option>Kitted</option><option>Delivered</option></select></div>
|
||
<div class="field"><label>Warehouse Owner</label><input type="text" id="wp_kit_owner" placeholder="name"></div>
|
||
<div class="field"><label>Kitting Need Date</label><input type="date" id="wp_kit_date"></div>
|
||
<div class="field"><label>MIMO Sch. Time</label><input type="datetime-local" id="wp_mimo_time"><div class="field-hint">scheduled material-move date & time</div></div>
|
||
<div class="field"><label>MIMO Location</label><input type="text" id="wp_mimo_loc" placeholder="staging / move location"></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- CONSTRAINTS / RELEASE READINESS -->
|
||
<div class="card" id="constraint-card">
|
||
<div class="sub-heading">Constraints — Release Readiness<span class="help-tip" data-tip="A package can't be Issued until every constraint is Cleared or N/A. If one reopens after release, the package drops to Issue (Hold).">i</span></div>
|
||
<div class="notice">Per AWP, a package is not released to the field until every constraint is <strong>Cleared</strong> or <strong>N/A</strong>. If a constraint reopens after release, status drops to <strong>Issue (Hold)</strong>.</div>
|
||
<div class="table-wrap"><table><thead><tr><th>Constraint</th><th style="width:230px">Status</th><th>Comment</th></tr></thead><tbody id="constraint-body"></tbody></table></div>
|
||
</div>
|
||
|
||
<!-- QUALITY & HOLD POINTS -->
|
||
<div class="card">
|
||
<div class="sub-heading">Quality, Inspection & Hold Points</div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>QC Required</label><input type="text" id="wp_qc" placeholder="from SOP" readonly>
|
||
<div class="lock-row"><button type="button" class="lock-edit" onclick="editQuality('wp_qc')">🔒 Edit (reason required)</button><span class="override-note"></span></div></div>
|
||
<div class="field"><label>Photo Documentation</label><input type="text" id="wp_photo" placeholder="from SOP" readonly>
|
||
<div class="lock-row"><button type="button" class="lock-edit" onclick="editQuality('wp_photo')">🔒 Edit (reason required)</button><span class="override-note"></span></div></div>
|
||
</div>
|
||
<div class="field field-grid col1"><div class="field"><label>Witness / Hold Points</label><textarea id="wp_hold" rows="2" readonly placeholder="from SOP"></textarea>
|
||
<div class="lock-row"><button type="button" class="lock-edit" onclick="editQuality('wp_hold')">🔒 Edit (reason required)</button><span class="override-note"></span></div>
|
||
<div class="field-hint">Inherited from the SOP. A <strong>Hold Point</strong> stops work until inspection sign-off; a <strong>Witness Point</strong> is offered for inspection but work may proceed if declined.</div></div></div>
|
||
</div>
|
||
|
||
<!-- SIGN-OFFS -->
|
||
<div class="card">
|
||
<div class="sub-heading">Approvals & Sign-offs</div>
|
||
<div class="notice">Per the AWP IWP checklist. A package should be signed by these roles before release.</div>
|
||
<div class="table-wrap"><table><thead><tr><th style="width:220px">Role</th><th>Name</th><th style="width:150px">Date</th><th style="width:80px;text-align:center">Signed</th></tr></thead><tbody id="signoff-body"></tbody></table></div>
|
||
</div>
|
||
|
||
<!-- CLOSEOUT -->
|
||
<div class="card" id="closeout-card">
|
||
<div class="sub-heading">Closeout</div>
|
||
<div class="notice">Completed at QC / Closed — captures as-built reality and lessons learned.</div>
|
||
<div class="field-grid">
|
||
<div class="field"><label>Actual Hrs.</label><input type="number" id="wp_actual_hrs" min="0" step="1"></div>
|
||
<div class="field"><label>Installed Quantity</label><input type="text" id="wp_installed_qty" placeholder="e.g. 42 of 42 tags"></div>
|
||
</div>
|
||
<div class="field field-grid col1"><div class="field"><label>Redlines / As-Built Notes</label><textarea id="wp_redlines" rows="2"></textarea></div></div>
|
||
<div class="field field-grid col1"><div class="field"><label>Lessons Learned</label><textarea id="wp_lessons" rows="2"></textarea></div></div>
|
||
</div>
|
||
|
||
<div class="nav-row"><button class="btn btn-ghost" onclick="newPackage()">↺ Clear</button>
|
||
<div style="display:flex;gap:10px">
|
||
<button class="btn btn-ghost" onclick="savePackage(false)">Save Draft</button>
|
||
<button class="btn btn-generate" onclick="savePackage(true)">⚡ Save & View</button>
|
||
</div></div>
|
||
|
||
<!-- DASHBOARD -->
|
||
<div id="dashboard-view" style="display:none">
|
||
<div class="output-toolbar">
|
||
<button class="btn btn-ghost" onclick="showForm()">← Back to Form</button>
|
||
<div style="font-weight:700;font-size:15px">Work Package Dashboard</div>
|
||
<div style="display:flex;gap:10px;margin-left:auto">
|
||
<button class="btn btn-ghost" onclick="newPackage()">+ New WP</button>
|
||
<button class="btn btn-ghost" onclick="renderDashboard()">↻ Refresh</button>
|
||
<button class="btn btn-ghost" onclick="exportPackages()">⤓ Export (JSON)</button>
|
||
</div>
|
||
</div>
|
||
<div class="ctx-bar" style="margin:0 0 14px"><div class="field-hint">Status, metrics and gating across all saved work packages on this device. <span style="color:var(--text-dim)">Reads local data now; wires to the shared SQL database in Phase 2.</span></div></div>
|
||
<div id="dash-body"></div>
|
||
</div>
|
||
|
||
<!-- OUTPUT -->
|
||
<div id="pkg-output" style="display:none">
|
||
<div class="output-toolbar">
|
||
<button class="btn btn-ghost" onclick="showForm()">← Back to Form</button>
|
||
<button class="btn btn-primary" onclick="printPackage()">⎙ Print / Save PDF</button>
|
||
<button class="btn btn-ghost" onclick="exportPackages()">⤓ Export (JSON)</button>
|
||
</div>
|
||
<div class="output-doc" id="pkg-doc"></div>
|
||
</div>
|
||
|
||
<!-- SAVED -->
|
||
<div class="card" id="saved-card" style="display:none">
|
||
<div class="sub-heading">Saved Work Packages <span id="saved-count"></span></div>
|
||
<div class="table-wrap"><table><thead><tr><th>WP #</th><th>Type</th><th>Subject</th><th>Status</th><th style="width:110px">Ready?</th><th style="width:120px"></th></tr></thead><tbody id="saved-body"></tbody></table></div>
|
||
<button class="add-btn" onclick="exportPackages()">⤓ Export All (JSON)</button>
|
||
<button class="add-btn" onclick="clearSaved()">Clear All</button>
|
||
</div>
|
||
|
||
</div>
|
||
</div>
|
||
|
||
<!-- HOLD LOG MODAL (comment 7) -->
|
||
<div class="modal-overlay" id="hold-modal">
|
||
<div class="modal">
|
||
<div class="modal-head"><div class="modal-title">Log Hold — On-Hold Constraint</div><button class="cmt-x" onclick="cancelHold()" title="Cancel">✕</button></div>
|
||
<div class="modal-body">
|
||
<div class="notice">Moving a package to <strong>Issue (Hold)</strong> requires logging the constraint that blocked it.</div>
|
||
<div class="field"><label>Constraint type <span class="req">*</span></label><select id="hold-constraint"></select></div>
|
||
<div class="field"><label>Details <span class="req">*</span></label><textarea id="hold-details" rows="3" placeholder="What reopened / blocked this package?"></textarea></div>
|
||
<div class="field"><label>Supporting document link</label><input type="text" id="hold-doclink" placeholder="link to RFI, photo, email, etc. (optional)"></div>
|
||
<div class="field"><label>Supporting photo</label><input type="file" id="hold-photo" accept="image/*" onchange="holdPhotoChange(event)"><div class="hold-photo-preview" id="hold-photo-preview"></div></div>
|
||
</div>
|
||
<div class="modal-foot"><button class="btn btn-ghost" onclick="cancelHold()">Cancel</button><button class="btn btn-generate" onclick="submitHold()">Log Hold</button></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- VIEW SOP MODAL (comment 2) -->
|
||
<div class="modal-overlay" id="sop-modal">
|
||
<div class="modal" style="max-width:640px">
|
||
<div class="modal-head"><div class="modal-title">Project SOP — Reference</div><button class="cmt-x" onclick="closeSopModal()" title="Close">✕</button></div>
|
||
<div class="modal-body" id="sop-modal-body"></div>
|
||
<div class="modal-foot"><button class="btn btn-primary" onclick="closeSopModal()">Close</button></div>
|
||
</div>
|
||
</div>
|
||
|
||
<!-- COMMENTS DRAWER -->
|
||
<div class="cmt-overlay" id="cmt-overlay" onclick="toggleComments()"></div>
|
||
<aside class="cmt-drawer" id="cmt-drawer" aria-hidden="true">
|
||
<div class="cmt-head"><div class="cmt-title">Review Comments</div><button class="cmt-x" onclick="toggleComments()" title="Close">✕</button></div>
|
||
<div class="cmt-namebar"><label>Your name</label><input type="text" id="cmt-author" placeholder="e.g. J. Park" oninput="cmtSaveAuthor(this.value)"></div>
|
||
<div class="cmt-compose"><div class="cmt-compose-label">Comment on <strong id="cmt-cur-step">this form</strong></div>
|
||
<textarea id="cmt-input" rows="3" placeholder="Add feedback…"></textarea>
|
||
<button class="btn btn-primary cmt-add" onclick="addComment()">Add Comment</button></div>
|
||
<div class="cmt-list" id="cmt-list"></div>
|
||
<div class="cmt-foot"><div class="cmt-note">Comments are saved in your browser. Use <strong>Export</strong> to send feedback back; the owner can <strong>Import</strong> each file.</div>
|
||
<div class="cmt-foot-btns"><button class="btn btn-ghost" onclick="exportComments()">⤓ Export</button>
|
||
<button class="btn btn-ghost" onclick="document.getElementById('cmt-import').click()">⤒ Import</button>
|
||
<button class="btn btn-ghost cmt-clear" onclick="clearMyComments()">Clear Mine</button>
|
||
<input type="file" id="cmt-import" accept="application/json" style="display:none" onchange="importComments(event)"></div></div>
|
||
</aside>
|
||
|
||
<!-- STICKY SAVE BAR (always-visible save + release status) -->
|
||
<div class="sticky-save" id="sticky-save" style="display:none">
|
||
<span class="sticky-status" id="sticky-status"></span>
|
||
<div class="sticky-actions">
|
||
<button class="btn btn-ghost" onclick="savePackage(false)">Save Draft</button>
|
||
<button class="btn btn-generate" onclick="savePackage(true)">⚡ Save & View</button>
|
||
</div>
|
||
</div>
|
||
|
||
<script src="feedback-config.js"></script>
|
||
<script src="project-data.js"></script>
|
||
<script src="help.js"></script>
|
||
<script src="wp-creation-app.js"></script>
|
||
<script src="wp-format.js"></script>
|
||
</body>
|
||
</html>
|