feat(spa): wire playout delete/reset/erase + scheduling context + templates preview calendar (#210)

Adds the SPA slice for the newly-merged playout endpoints:
- api/playouts: deletePlayout, resetChannelPlayout, erasePlayoutItems,
  erasePlayoutItemsAndHistory, getPlayoutItemSchedulingContext (+ types).
- PlayoutsScreen: enable per-playout Reset (channel playout reset), Delete
  (danger, confirm), and erase-by-kind buttons (Block = items + items&history;
  Classic/Sequential/Scripted = items&history; none for ExternalJson); replaces
  the stale "no per-playout reset endpoint" block. Disable Alternate schedules
  for OnDemand Classic playouts (Blazor parity).
- Per-item scheduling-context dialog (info button when hasSchedulingContext &&
  id != null), rendering the decoded JSON in a scrollable <pre>.
- Playout-templates editor: "Preview calendar" toggle with a Monday-first month
  grid; winning template per day computed client-side via a colocated
  appliesToDate/firstMatchingIndex helper that ports
  AlternateScheduleSelector.GetScheduleForDate / PlayoutTemplateEditViewModel
  .AppliesToDate exactly (inclusive range, year-wrap reverse, start-day rollover,
  end-day clamp, explicit-year override).
- Button gains a title prop (parity with IconButton) for the disabled-button hint.

Tests: api client URL/method assertions, PlayoutsScreen action flows
(delete/reset/erase per kind, OnDemand gating, scheduling-context dialog +
error), calendar-helper unit tests, and a preview-calendar render test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-07-09 22:30:28 +02:00
co-authored by Claude Fable 5
parent e66b926206
commit 91e23bcd57
9 changed files with 873 additions and 15 deletions
+4 -1
View File
@@ -20,6 +20,7 @@ export interface ButtonProps {
type?: 'button' | 'submit' | 'reset';
onClick?: (e: MouseEvent<HTMLButtonElement>) => void;
style?: CSSProperties;
title?: string;
}
export function Button({
@@ -33,13 +34,15 @@ export function Button({
fullWidth = false,
type = 'button',
onClick,
style
style,
title
}: ButtonProps) {
return (
<button
type={type}
disabled={disabled || loading}
onClick={onClick}
title={title}
className={classNames(
'ctv-button',
`ctv-button-${variant}`,