Replace offset year/month spinners with type picklist + value input
Offset Type: [Year|Month|Week|Day] Offset Value: [n] Cleaner UX, handles all interval types uniformly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
d4962f4376
commit
d49aac70e4
@ -557,8 +557,8 @@ async function openBaselineWorkbench() {
|
|||||||
|
|
||||||
// reset form
|
// reset form
|
||||||
document.getElementById('seg-description').value = '';
|
document.getElementById('seg-description').value = '';
|
||||||
document.getElementById('seg-offset-years').value = '0';
|
document.getElementById('seg-offset-type').value = '';
|
||||||
document.getElementById('seg-offset-months').value = '0';
|
document.getElementById('seg-offset-value').value = '0';
|
||||||
document.getElementById('seg-filter-rows').innerHTML = '';
|
document.getElementById('seg-filter-rows').innerHTML = '';
|
||||||
document.getElementById('seg-timeline').classList.add('hidden');
|
document.getElementById('seg-timeline').classList.add('hidden');
|
||||||
addFilterRow(); // start with one empty filter row
|
addFilterRow(); // start with one empty filter row
|
||||||
@ -727,11 +727,23 @@ function updateTimelinePreview() {
|
|||||||
|
|
||||||
const months = (to.getFullYear() - from.getFullYear()) * 12 + (to.getMonth() - from.getMonth()) + 1;
|
const months = (to.getFullYear() - from.getFullYear()) * 12 + (to.getMonth() - from.getMonth()) + 1;
|
||||||
const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: 'numeric' });
|
const fmt = new Intl.DateTimeFormat('en-US', { month: 'short', year: 'numeric' });
|
||||||
const offsetYears = parseInt(document.getElementById('seg-offset-years').value) || 0;
|
const offsetType = document.getElementById('seg-offset-type').value;
|
||||||
const offsetMonths = parseInt(document.getElementById('seg-offset-months').value) || 0;
|
const offsetValue = parseInt(document.getElementById('seg-offset-value').value) || 0;
|
||||||
|
|
||||||
const projFrom = new Date(from); projFrom.setFullYear(projFrom.getFullYear() + offsetYears); projFrom.setMonth(projFrom.getMonth() + offsetMonths);
|
function applyOffset(d) {
|
||||||
const projTo = new Date(to); projTo.setFullYear(projTo.getFullYear() + offsetYears); projTo.setMonth(projTo.getMonth() + offsetMonths);
|
const r = new Date(d);
|
||||||
|
if (!offsetType || !offsetValue) return r;
|
||||||
|
switch (offsetType) {
|
||||||
|
case 'year': r.setFullYear(r.getFullYear() + offsetValue); break;
|
||||||
|
case 'month': r.setMonth(r.getMonth() + offsetValue); break;
|
||||||
|
case 'week': r.setDate(r.getDate() + offsetValue * 7); break;
|
||||||
|
case 'day': r.setDate(r.getDate() + offsetValue); break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
const projFrom = applyOffset(from);
|
||||||
|
const projTo = applyOffset(to);
|
||||||
|
|
||||||
let html = `
|
let html = `
|
||||||
<div class="timeline-row">
|
<div class="timeline-row">
|
||||||
@ -746,12 +758,9 @@ function updateTimelinePreview() {
|
|||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|
||||||
if (offsetYears || offsetMonths) {
|
if (offsetType && offsetValue) {
|
||||||
const parts = [];
|
|
||||||
if (offsetYears) parts.push(`${offsetYears} yr`);
|
|
||||||
if (offsetMonths) parts.push(`${offsetMonths} mo`);
|
|
||||||
html += `
|
html += `
|
||||||
<div class="timeline-offset-indicator">+ ${parts.join(' ')} →</div>
|
<div class="timeline-offset-indicator">+ ${offsetValue} ${offsetType}${offsetValue !== 1 ? 's' : ''} →</div>
|
||||||
<div class="timeline-row">
|
<div class="timeline-row">
|
||||||
<div class="timeline-row-label">Projected</div>
|
<div class="timeline-row-label">Projected</div>
|
||||||
<div class="timeline-bar-wrap">
|
<div class="timeline-bar-wrap">
|
||||||
@ -774,12 +783,11 @@ async function submitBaselineSegment() {
|
|||||||
const filters = getFilterRows();
|
const filters = getFilterRows();
|
||||||
if (filters.length === 0) { showStatus('Add at least one filter', 'error'); return; }
|
if (filters.length === 0) { showStatus('Add at least one filter', 'error'); return; }
|
||||||
|
|
||||||
const years = parseInt(document.getElementById('seg-offset-years').value) || 0;
|
const offsetType = document.getElementById('seg-offset-type').value;
|
||||||
const months = parseInt(document.getElementById('seg-offset-months').value) || 0;
|
const offsetValue = parseInt(document.getElementById('seg-offset-value').value) || 0;
|
||||||
const parts = [];
|
const date_offset = (offsetType && offsetValue)
|
||||||
if (years) parts.push(`${years} year${years !== 1 ? 's' : ''}`);
|
? `${offsetValue} ${offsetType}${offsetValue !== 1 ? 's' : ''}`
|
||||||
if (months) parts.push(`${months} month${months !== 1 ? 's' : ''}`);
|
: '0 days';
|
||||||
const date_offset = parts.length ? parts.join(' ') : '0 days';
|
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
filters,
|
filters,
|
||||||
@ -1278,8 +1286,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
document.getElementById('btn-add-filter-row').addEventListener('click', addFilterRow);
|
document.getElementById('btn-add-filter-row').addEventListener('click', addFilterRow);
|
||||||
document.getElementById('btn-load-segment').addEventListener('click', submitBaselineSegment);
|
document.getElementById('btn-load-segment').addEventListener('click', submitBaselineSegment);
|
||||||
document.getElementById('btn-clear-baseline').addEventListener('click', clearBaseline);
|
document.getElementById('btn-clear-baseline').addEventListener('click', clearBaseline);
|
||||||
document.getElementById('seg-offset-years').addEventListener('input', updateTimelinePreview);
|
document.getElementById('seg-offset-type').addEventListener('change', updateTimelinePreview);
|
||||||
document.getElementById('seg-offset-months').addEventListener('input', updateTimelinePreview);
|
document.getElementById('seg-offset-value').addEventListener('input', updateTimelinePreview);
|
||||||
|
|
||||||
// undo in baseline segments list
|
// undo in baseline segments list
|
||||||
document.getElementById('baseline-segments-list').addEventListener('click', async e => {
|
document.getElementById('baseline-segments-list').addEventListener('click', async e => {
|
||||||
|
|||||||
@ -111,11 +111,17 @@
|
|||||||
<input type="text" id="seg-description" placeholder="e.g. All orders FY2024" />
|
<input type="text" id="seg-description" placeholder="e.g. All orders FY2024" />
|
||||||
</label>
|
</label>
|
||||||
<div class="offset-row">
|
<div class="offset-row">
|
||||||
<label class="baseline-field-label">Offset Years
|
<label class="baseline-field-label">Offset Type
|
||||||
<input type="number" id="seg-offset-years" min="0" value="0" />
|
<select id="seg-offset-type">
|
||||||
|
<option value="">— none —</option>
|
||||||
|
<option value="year">Year</option>
|
||||||
|
<option value="month">Month</option>
|
||||||
|
<option value="week">Week</option>
|
||||||
|
<option value="day">Day</option>
|
||||||
|
</select>
|
||||||
</label>
|
</label>
|
||||||
<label class="baseline-field-label">Offset Months
|
<label class="baseline-field-label">Offset Value
|
||||||
<input type="number" id="seg-offset-months" min="0" value="0" />
|
<input type="number" id="seg-offset-value" min="0" value="0" />
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="filter-section">
|
<div class="filter-section">
|
||||||
|
|||||||
@ -478,12 +478,14 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.baseline-field-label input[type=text],
|
.baseline-field-label input[type=text],
|
||||||
.baseline-field-label input[type=number] {
|
.baseline-field-label input[type=number],
|
||||||
|
.baseline-field-label select {
|
||||||
border: 1px solid #dce1e7;
|
border: 1px solid #dce1e7;
|
||||||
padding: 5px 8px;
|
padding: 5px 8px;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
color: #333;
|
color: #333;
|
||||||
|
background: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.offset-row { display: flex; gap: 10px; }
|
.offset-row { display: flex; gap: 10px; }
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user