pf_app/public/index.html
Paul Trowbridge 5550a57f97 Add baseline workbench — multi-segment additive baseline with filter builder
- New Baseline nav view replaces the simple Load Baseline modal
- Baseline loads are now additive; each segment is independently undoable
- Filter builder: any date/filter-role column, full operator set
- Timeline preview shows source → projected period bars for date BETWEEN filters
- Clear Baseline action deletes all baseline rows and log entries
- DELETE /api/versions/:id/baseline route
- buildFilterClause() added to sql_generator
- filter role added to col_meta editor
- Reminder: re-run generate-sql for each source after this change

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 13:27:36 -04:00

268 lines
13 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Pivot Forecast</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ag-grid-community@31.0.0/styles/ag-grid.css">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/ag-grid-community@31.0.0/styles/ag-theme-alpine.css">
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="app">
<!-- Sidebar -->
<nav id="sidebar">
<div class="sidebar-brand">Pivot Forecast</div>
<ul class="nav-links">
<li data-view="sources" class="active">Sources</li>
<li data-view="versions">Versions</li>
<li data-view="baseline">Baseline</li>
<li data-view="forecast">Forecast</li>
<li data-view="log">Log</li>
</ul>
<div class="sidebar-context">
<div id="ctx-source" class="ctx-item hidden">
<span class="ctx-label">Source</span>
<span id="ctx-source-name"></span>
</div>
<div id="ctx-version" class="ctx-item hidden">
<span class="ctx-label">Version</span>
<span id="ctx-version-name"></span>
<span id="ctx-version-status" class="status-badge"></span>
</div>
</div>
<div class="sidebar-user">
<label>User</label>
<input type="text" id="input-pf-user" placeholder="your name" />
</div>
</nav>
<!-- Main content -->
<main id="content">
<div id="status-bar" class="hidden"></div>
<!-- ===== SOURCES VIEW ===== -->
<div id="view-sources" class="view active">
<div class="two-col-layout">
<div class="panel">
<div class="panel-header">
<span>Database Tables</span>
<div class="header-actions">
<button id="btn-register" class="btn btn-primary hidden">Register Table</button>
</div>
</div>
<div id="tables-grid" class="ag-theme-alpine grid-fill"></div>
</div>
<div class="panel">
<div class="panel-header">
<span id="right-panel-title">Registered Sources</span>
<div class="header-actions">
<button id="btn-back-sources" class="btn hidden">← Sources</button>
<button id="btn-save-cols" class="btn hidden">Save Columns</button>
<button id="btn-generate-sql" class="btn btn-primary hidden">Generate SQL</button>
</div>
</div>
<div id="sources-list-grid" class="ag-theme-alpine grid-fill"></div>
<div id="col-meta-grid" class="ag-theme-alpine grid-fill hidden"></div>
</div>
</div>
</div>
<!-- ===== VERSIONS VIEW ===== -->
<div id="view-versions" class="view hidden">
<div class="view-toolbar">
<span id="versions-source-label"></span>
<button id="btn-new-version" class="btn btn-primary">New Version</button>
</div>
<div id="new-version-form" class="inline-form hidden">
<h3>Create Version</h3>
<div class="form-row">
<label>Name<input type="text" id="ver-name" placeholder="e.g. FY2025 v1" /></label>
<label>Description<input type="text" id="ver-desc" placeholder="optional" /></label>
</div>
<div class="form-actions">
<button id="btn-create-version" class="btn btn-primary">Create</button>
<button id="btn-cancel-version" class="btn">Cancel</button>
</div>
</div>
<div id="versions-grid" class="ag-theme-alpine"></div>
<div id="version-actions" class="version-actions hidden">
<span id="version-actions-label"></span>
<button class="btn btn-primary" id="vbtn-forecast">Open Forecast</button>
<button class="btn" id="vbtn-baseline">Load Baseline</button>
<button class="btn" id="vbtn-reference">Load Reference</button>
<button class="btn" id="vbtn-toggle">Close Version</button>
<button class="btn btn-danger" id="vbtn-delete">Delete</button>
</div>
</div>
<!-- ===== BASELINE WORKBENCH VIEW ===== -->
<div id="view-baseline" class="view hidden">
<div class="workbench-toolbar">
<span id="baseline-label">No version selected</span>
<button id="btn-clear-baseline" class="btn btn-danger">Clear Baseline</button>
</div>
<div class="baseline-layout">
<div class="baseline-form-panel">
<div class="panel-section-title">Add Segment</div>
<div class="baseline-form">
<label class="baseline-field-label">Description
<input type="text" id="seg-description" placeholder="e.g. All orders FY2024" />
</label>
<div class="offset-row">
<label class="baseline-field-label">Offset Years
<input type="number" id="seg-offset-years" min="0" value="0" />
</label>
<label class="baseline-field-label">Offset Months
<input type="number" id="seg-offset-months" min="0" value="0" />
</label>
</div>
<div class="filter-section">
<div class="filter-section-label">Filters <span class="required-star">*</span></div>
<div id="seg-filter-rows"></div>
<button id="btn-add-filter-row" class="btn btn-sm">+ Add Filter</button>
</div>
<div id="seg-timeline" class="timeline-preview hidden"></div>
<button id="btn-load-segment" class="btn btn-primary">Load Segment</button>
</div>
</div>
<div class="baseline-segments-panel">
<div class="panel-section-title">Loaded Segments</div>
<div id="baseline-segments-list">
<div class="segments-empty">No segments loaded yet.</div>
</div>
</div>
</div>
</div>
<!-- ===== FORECAST VIEW ===== -->
<div id="view-forecast" class="view hidden">
<div class="forecast-toolbar">
<span id="forecast-label">No version selected</span>
<button id="btn-forecast-refresh" class="btn">Refresh</button>
<button id="btn-expand-all" class="btn">Expand All</button>
<button id="btn-collapse-all" class="btn">Collapse All</button>
</div>
<div class="forecast-layout">
<div id="pivot-panel">
<div id="pivot-grid" class="ag-theme-alpine"></div>
</div>
<div id="operation-panel">
<div class="op-section">
<div class="op-title">Slice</div>
<div id="slice-display">
<span class="op-hint">Click a row to select a slice</span>
</div>
<button id="btn-clear-slice" class="btn btn-sm hidden">Clear</button>
</div>
<div id="op-forms-area" class="hidden">
<div class="op-tabs">
<button class="op-tab active" data-op="scale">Scale</button>
<button class="op-tab" data-op="recode">Recode</button>
<button class="op-tab" data-op="clone">Clone</button>
</div>
<!-- Scale -->
<div id="op-scale" class="op-form">
<label>Value Δ<input type="number" id="scale-value-incr" step="any" placeholder="0" /></label>
<label>Units Δ<input type="number" id="scale-units-incr" step="any" placeholder="0" /></label>
<label class="label-inline"><input type="checkbox" id="scale-pct" /> Treat as %</label>
<label>Note<input type="text" id="scale-note" placeholder="optional" /></label>
<button id="btn-submit-scale" class="btn btn-primary">Apply Scale</button>
</div>
<!-- Recode -->
<div id="op-recode" class="op-form hidden">
<div class="op-hint">Enter new values for dimensions to replace:</div>
<div id="recode-fields"></div>
<label>Note<input type="text" id="recode-note" placeholder="optional" /></label>
<button id="btn-submit-recode" class="btn btn-primary">Apply Recode</button>
</div>
<!-- Clone -->
<div id="op-clone" class="op-form hidden">
<div class="op-hint">Override dimension values on cloned rows:</div>
<div id="clone-fields"></div>
<label>Scale Factor<input type="number" id="clone-scale" step="any" value="1" /></label>
<label>Note<input type="text" id="clone-note" placeholder="optional" /></label>
<button id="btn-submit-clone" class="btn btn-primary">Apply Clone</button>
</div>
</div>
</div>
</div>
</div>
<!-- ===== LOG VIEW ===== -->
<div id="view-log" class="view hidden">
<div id="log-grid" class="ag-theme-alpine grid-fill"></div>
</div>
</main>
</div>
<!-- Load baseline / reference modal -->
<div id="load-data-modal" class="modal-overlay hidden">
<div class="modal load-data-modal">
<div class="modal-header">
<span id="load-data-title">Load Baseline</span>
<button id="btn-load-close" class="btn-icon">×</button>
</div>
<div id="load-data-body">
<div class="load-form-fields">
<label>Date From<input type="date" id="load-date-from" /></label>
<label>Date To<input type="date" id="load-date-to" /></label>
<div id="load-offset-fields">
<div class="load-offset-row">
<label>Offset Years<input type="number" id="load-offset-years" min="0" value="0" /></label>
<label>Offset Months<input type="number" id="load-offset-months" min="0" value="0" /></label>
</div>
</div>
<label>Note<input type="text" id="load-note" placeholder="optional" /></label>
</div>
<div id="load-date-preview" class="load-date-preview hidden">
<!-- reference: single chip list -->
<div id="load-preview-simple">
<div class="load-preview-label"></div>
<div id="load-date-chips" class="date-chips"></div>
</div>
<!-- baseline: before → after -->
<div id="load-preview-offset" class="hidden">
<div class="load-preview-columns">
<div class="load-preview-col">
<div class="load-preview-label">Source</div>
<div id="load-chips-source" class="date-chips"></div>
</div>
<div class="load-preview-arrow"></div>
<div class="load-preview-col">
<div class="load-preview-label">Projected</div>
<div id="load-chips-projected" class="date-chips"></div>
</div>
</div>
</div>
</div>
</div>
<div class="modal-footer">
<button id="btn-load-submit" class="btn btn-primary">Load</button>
<button id="btn-load-cancel" class="btn">Cancel</button>
</div>
</div>
</div>
<!-- Table preview modal -->
<div id="modal-overlay" class="modal-overlay hidden">
<div class="modal">
<div class="modal-header">
<span id="modal-title">Preview</span>
<button id="modal-close" class="btn-icon">×</button>
</div>
<div id="modal-body"></div>
<div class="modal-footer">
<button id="btn-modal-register" class="btn btn-primary">Register This Table</button>
<button id="btn-modal-close" class="btn">Close</button>
</div>
</div>
</div>
<script src="https://cdn.jsdelivr.net/npm/ag-grid-enterprise@31.0.0/dist/ag-grid-enterprise.min.js"></script>
<script src="app.js"></script>
</body>
</html>