diff --git a/cmd/qrunproxy/static/index.html b/cmd/qrunproxy/static/index.html index 769c282..63f134f 100644 --- a/cmd/qrunproxy/static/index.html +++ b/cmd/qrunproxy/static/index.html @@ -164,7 +164,10 @@ function render(data) { `QLab Connected`; const timeline = document.getElementById('timeline'); - timeline.style.gridTemplateColumns = `repeat(${data.tracks.length}, 140px)`; + const numTracks = data.tracks.length; + const numRows = Math.max(...data.tracks.map(t => t.cells.length)); + timeline.style.gridTemplateColumns = `repeat(${numTracks}, 140px)`; + data.tracks.forEach(track => { const el = document.createElement('div'); el.className = 'track-header'; @@ -172,12 +175,13 @@ function render(data) { timeline.appendChild(el); }); - data.rows.forEach((row, rowIndex) => { - const hasCue = row.cells.some(c => c.block_id && c.event && (data.blocks[c.block_id] || {}).type === 'cue'); - const hasSignal = !hasCue && row.cells.some(c => c.event && c.is_signal); + for (let r = 0; r < numRows; r++) { + const cells = data.tracks.map(t => t.cells[r] || {}); + const hasCue = cells.some(c => c.block_id && c.event && (data.blocks[c.block_id] || {}).type === 'cue'); + const hasSignal = !hasCue && cells.some(c => c.event && c.is_signal); const rowCls = hasCue ? ' cue-row' : (hasSignal ? ' sig-row' : ''); - row.cells.forEach(c => { + cells.forEach(c => { const div = document.createElement('div'); div.className = 'cell' + rowCls; if (c.is_title) { @@ -185,7 +189,7 @@ function render(data) { div.innerHTML = `
${block.name || ''}
`; } else if (c.block_id) { const block = data.blocks[c.block_id] || {}; - const isInfinity = rowIndex === data.rows.length - 1 && !c.is_end && !c.is_title; + const isInfinity = r === numRows - 1 && !c.is_end && !c.is_title; let seg = 'mid'; if (c.is_start && c.is_end) seg = 'single'; else if (c.is_start) seg = 'start'; @@ -206,7 +210,7 @@ function render(data) { } timeline.appendChild(div); }); - }); + } } diff --git a/cmd/qrunproxy/timeline.go b/cmd/qrunproxy/timeline.go index 5e1cc4c..a2f5835 100644 --- a/cmd/qrunproxy/timeline.go +++ b/cmd/qrunproxy/timeline.go @@ -40,14 +40,14 @@ type TriggerTarget struct { Hook string `json:"hook"` } -type Timeline struct { - Tracks []Track `json:"tracks"` - Blocks map[string]Block `json:"blocks"` - Rows []TimelineRow `json:"rows"` +type TimelineTrack struct { + Track + Cells []TimelineCell `json:"cells"` } -type TimelineRow struct { - Cells []TimelineCell `json:"cells"` +type Timeline struct { + Tracks []TimelineTrack `json:"tracks"` + Blocks map[string]Block `json:"blocks"` } type TimelineCell struct { @@ -150,10 +150,14 @@ func BuildTimeline(show Show) (Timeline, error) { b.assignRows() b.collapseEmptyRows() + tracks := make([]TimelineTrack, len(b.tracks)) + for i, t := range b.tracks { + tracks[i] = TimelineTrack{Track: t, Cells: b.trackCells[i]} + } + return Timeline{ - Tracks: b.tracks, + Tracks: tracks, Blocks: b.blocks, - Rows: b.renderRows(), }, nil } @@ -340,10 +344,22 @@ func (b *timelineBuilder) insertGap(track, beforeIndex int) { } } + gap := TimelineCell{IsGap: true} + for i := beforeIndex - 1; i >= 0; i-- { + c := b.trackCells[track][i] + if c.IsGap { + continue + } + if c.BlockID != "" && !c.IsEnd { + gap.BlockID = c.BlockID + } + break + } + cells := b.trackCells[track] newCells := make([]TimelineCell, 0, len(cells)+1) newCells = append(newCells, cells[:beforeIndex]...) - newCells = append(newCells, TimelineCell{IsGap: true}) + newCells = append(newCells, gap) newCells = append(newCells, cells[beforeIndex:]...) b.trackCells[track] = newCells @@ -435,41 +451,3 @@ func (b *timelineBuilder) collapseEmptyRows() { } } -func (b *timelineBuilder) renderRows() []TimelineRow { - maxLen := 0 - for _, cells := range b.trackCells { - if len(cells) > maxLen { - maxLen = len(cells) - } - } - - rows := make([]TimelineRow, maxLen) - for r := range rows { - rows[r].Cells = make([]TimelineCell, len(b.tracks)) - } - - for trackIdx, cells := range b.trackCells { - activeBlock := "" - for r := 0; r < maxLen; r++ { - if r < len(cells) { - c := cells[r] - if c.IsGap { - if activeBlock != "" { - rows[r].Cells[trackIdx] = TimelineCell{BlockID: activeBlock} - } - } else { - rows[r].Cells[trackIdx] = c - if c.BlockID != "" && !c.IsEnd { - activeBlock = c.BlockID - } else if c.IsEnd { - activeBlock = "" - } - } - } else if activeBlock != "" { - rows[r].Cells[trackIdx] = TimelineCell{BlockID: activeBlock} - } - } - } - - return rows -}