* refactor classic and block schedules to use same alternate schedule selector * handle start year and end year * add migrations for classic and block schedules * allow editing block template start and end year * add tests that include years * add date range editing to classic (alternate) schedules * fix running tests locally * restore media files load; needed for local folder scanners * update changelog * feedback
602 lines
26 KiB
Plaintext
602 lines
26 KiB
Plaintext
@page "/playouts/{Id:int}/templates"
|
|
@using System.Globalization
|
|
@using System.Text
|
|
@using ErsatzTV.Application.Channels
|
|
@using ErsatzTV.Application.Scheduling
|
|
@using ErsatzTV.Core.Scheduling
|
|
@implements IDisposable
|
|
@inject NavigationManager NavigationManager
|
|
@inject ILogger<PlayoutTemplatesEditor> Logger
|
|
@inject ISnackbar Snackbar
|
|
@inject IMediator Mediator
|
|
|
|
<MudForm Style="max-height: 100%">
|
|
<MudPaper Square="true" Style="display: flex; height: 64px; min-height: 64px; width: 100%; z-index: 100; align-items: center">
|
|
<div style="display: flex; flex-direction: row; margin-bottom: auto; margin-top: auto; width: 100%; align-items: center" class="ml-6 mr-6">
|
|
<div class="d-none d-md-flex">
|
|
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SaveChanges())" StartIcon="@Icons.Material.Filled.Save">
|
|
Save Templates
|
|
</MudButton>
|
|
<MudButton Class="ml-3" Variant="Variant.Filled" Color="Color.Default" OnClick="@(_ => AddTemplate())" StartIcon="@Icons.Material.Filled.PlaylistAdd">
|
|
Add Template
|
|
</MudButton>
|
|
<MudButton Class="ml-3" Variant="Variant.Filled" Color="Color.Secondary" OnClick="@(_ => PreviewCalendar())" StartIcon="@Icons.Material.Filled.Preview">
|
|
Preview Calendar
|
|
</MudButton>
|
|
</div>
|
|
<div style="align-items: center; display: flex; margin-left: auto;" class="d-md-none">
|
|
<div class="flex-grow-1"></div>
|
|
<MudMenu Icon="@Icons.Material.Filled.MoreVert">
|
|
<MudMenuItem Icon="@Icons.Material.Filled.Save" Label="Save Templates" OnClick="@SaveChanges"/>
|
|
<MudMenuItem Icon="@Icons.Material.Filled.PlaylistAdd" Label="Add Template" OnClick="AddTemplate"/>
|
|
<MudMenuItem Icon="@Icons.Material.Filled.Preview" Label="Preview Calendar" OnClick="PreviewCalendar"/>
|
|
</MudMenu>
|
|
</div>
|
|
</div>
|
|
</MudPaper>
|
|
<div class="d-flex flex-column" style="height: 100vh; overflow-x: auto">
|
|
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
|
<MudText Typo="Typo.h5" Class="mb-2">@_channelName - Templates</MudText>
|
|
<MudDivider Class="mb-6"/>
|
|
<MudText Typo="Typo.body2" Class="mb-6">In priority order from top to bottom.</MudText>
|
|
<MudTable T="PlayoutTemplateEditViewModel" Class="mt-4" Hover="true" Items="_items.OrderBy(i => i.Index)" Dense="true" SelectedItem="@_selectedItem" SelectedItemChanged="@(vm => SelectedItemChanged(vm))" RowClassFunc="@SelectedRowClassFunc">
|
|
<ColGroup>
|
|
<MudHidden Breakpoint="Breakpoint.Xs">
|
|
<col/>
|
|
<col/>
|
|
<col/>
|
|
<col/>
|
|
<col style="width: 180px;"/>
|
|
</MudHidden>
|
|
</ColGroup>
|
|
<HeaderContent>
|
|
<MudTh>Template</MudTh>
|
|
<MudTh>Days of the Week</MudTh>
|
|
<MudTh>Days of the Month</MudTh>
|
|
<MudTh>Months</MudTh>
|
|
<MudTh/>
|
|
</HeaderContent>
|
|
<RowTemplate>
|
|
<MudTd>
|
|
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
|
|
@context.Template?.Name
|
|
</MudText>
|
|
</MudTd>
|
|
<MudTd>
|
|
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
|
|
@ToDaysOfWeekString(context.DaysOfWeek)
|
|
</MudText>
|
|
</MudTd>
|
|
<MudTd>
|
|
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
|
|
@ToDaysOfMonthString(context.DaysOfMonth)
|
|
</MudText>
|
|
</MudTd>
|
|
<MudTd>
|
|
<MudText Typo="@(context == _selectedItem ? Typo.subtitle2 : Typo.body2)">
|
|
@ToMonthsOfYearString(context.MonthsOfYear)
|
|
</MudText>
|
|
</MudTd>
|
|
<MudTd>
|
|
<div class="d-flex">
|
|
<MudIconButton Icon="@Icons.Material.Filled.ArrowUpward"
|
|
OnClick="@(_ => MoveItemUp(context))"
|
|
Disabled="@(_items.All(x => x.Index >= context.Index))">
|
|
</MudIconButton>
|
|
<MudIconButton Icon="@Icons.Material.Filled.ArrowDownward"
|
|
OnClick="@(_ => MoveItemDown(context))"
|
|
Disabled="@(_items.All(x => x.Index <= context.Index))">
|
|
</MudIconButton>
|
|
<MudIconButton Icon="@Icons.Material.Filled.Delete"
|
|
OnClick="@(_ => DeleteTemplate(context))">
|
|
</MudIconButton>
|
|
</div>
|
|
</MudTd>
|
|
</RowTemplate>
|
|
</MudTable>
|
|
@if (_selectedItem is not null)
|
|
{
|
|
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Edit Template</MudText>
|
|
<MudDivider Class="mb-6"/>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Template Group</MudText>
|
|
</div>
|
|
<MudSelect T="TemplateGroupViewModel" Value="@_selectedGroup" ValueChanged="@(vm => UpdateTemplateGroupItems(vm))">
|
|
@foreach (TemplateGroupViewModel templateGroup in _templateGroups)
|
|
{
|
|
<MudSelectItem Value="@templateGroup">
|
|
@templateGroup.Name
|
|
</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Template</MudText>
|
|
</div>
|
|
<MudSelect @bind-Value="_selectedItem.Template" For="@(() => _selectedItem.Template)">
|
|
@foreach (TemplateViewModel template in _templates)
|
|
{
|
|
<MudSelectItem Value="@template">@template.Name</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Deco Template Group</MudText>
|
|
</div>
|
|
<MudSelect T="DecoTemplateGroupViewModel" Value="@_selectedDecoTemplateGroup" ValueChanged="@(vm => UpdateDecoTemplateGroupItems(vm))">
|
|
@foreach (DecoTemplateGroupViewModel decoTemplateGroup in _decoTemplateGroups)
|
|
{
|
|
<MudSelectItem Value="@decoTemplateGroup">
|
|
@decoTemplateGroup.Name
|
|
</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Deco Template</MudText>
|
|
</div>
|
|
<MudSelect @bind-Value="_selectedItem.DecoTemplate" For="@(() => _selectedItem.DecoTemplate)" Clearable="true">
|
|
@foreach (DecoTemplateViewModel decoTemplate in _decoTemplates)
|
|
{
|
|
<MudSelectItem Value="@decoTemplate">@decoTemplate.Name</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Limit to Date Range</MudText>
|
|
</div>
|
|
<MudCheckBox T="bool" @bind-Value="_selectedItem.LimitToDateRange" Dense="true"/>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Start Day</MudText>
|
|
</div>
|
|
<MudSelect T="int" @bind-Value="_selectedItem.StartMonth" Disabled="@(!_selectedItem.LimitToDateRange)">
|
|
@foreach (int month in Enumerable.Range(1, 12))
|
|
{
|
|
<MudSelectItem Value="@month">@_dtf.GetMonthName(month)</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex"></div>
|
|
<MudSelect T="int" @bind-Value="_selectedItem.StartDay" Disabled="@(!_selectedItem.LimitToDateRange)">
|
|
@foreach (int day in Enumerable.Range(1, 31))
|
|
{
|
|
<MudSelectItem Value="@day">@day.ToString()</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex"></div>
|
|
<MudSelect T="int?" @bind-Value="_selectedItem.StartYear" Disabled="@(!_selectedItem.LimitToDateRange)" Clearable="true">
|
|
@foreach (int year in Enumerable.Range(DateTime.Today.Year, 50))
|
|
{
|
|
<MudSelectItem T="int?" Value="@year">@year.ToString()</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>End Day</MudText>
|
|
</div>
|
|
<MudSelect T="int" @bind-Value="_selectedItem.EndMonth" Disabled="@(!_selectedItem.LimitToDateRange)">
|
|
@foreach (int month in Enumerable.Range(1, 12))
|
|
{
|
|
<MudSelectItem Value="@month">@_dtf.GetMonthName(month)</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex"></div>
|
|
<MudSelect T="int" @bind-Value="_selectedItem.EndDay" Disabled="@(!_selectedItem.LimitToDateRange)">
|
|
@foreach (int day in Enumerable.Range(1, 31))
|
|
{
|
|
<MudSelectItem Value="@day">@day.ToString()</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex"></div>
|
|
<MudSelect T="int?" @bind-Value="_selectedItem.EndYear" Disabled="@(!_selectedItem.LimitToDateRange)" Clearable="true">
|
|
@foreach (int year in Enumerable.Range(DateTime.Today.Year, 50))
|
|
{
|
|
<MudSelectItem T="int?" Value="@year">@year.ToString()</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Days of the Week</MudText>
|
|
</div>
|
|
<MudSelect T="DayOfWeek" SelectedValues="@_selectedItem.DaysOfWeek" SelectedValuesChanged="OnSelectedDaysChanged" MultiSelection="true" Clearable="true" SelectAll="true" SelectAllText="Select All Days">
|
|
<MudSelectItem Value="@DayOfWeek.Monday">@_dtf.GetDayName(DayOfWeek.Monday)</MudSelectItem>
|
|
<MudSelectItem Value="@DayOfWeek.Tuesday">@_dtf.GetDayName(DayOfWeek.Tuesday)</MudSelectItem>
|
|
<MudSelectItem Value="@DayOfWeek.Wednesday">@_dtf.GetDayName(DayOfWeek.Wednesday)</MudSelectItem>
|
|
<MudSelectItem Value="@DayOfWeek.Thursday">@_dtf.GetDayName(DayOfWeek.Thursday)</MudSelectItem>
|
|
<MudSelectItem Value="@DayOfWeek.Friday">@_dtf.GetDayName(DayOfWeek.Friday)</MudSelectItem>
|
|
<MudSelectItem Value="@DayOfWeek.Saturday">@_dtf.GetDayName(DayOfWeek.Saturday)</MudSelectItem>
|
|
<MudSelectItem Value="@DayOfWeek.Sunday">@_dtf.GetDayName(DayOfWeek.Sunday)</MudSelectItem>
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex"></div>
|
|
<MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@(_ => SelectWeekdays())">
|
|
Weekdays
|
|
</MudButton>
|
|
<MudButton Variant="Variant.Filled" Color="Color.Secondary" OnClick="@(_ => SelectWeekends())">
|
|
Weekends
|
|
</MudButton>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Days of the Month</MudText>
|
|
</div>
|
|
<MudSelect T="int" SelectedValues="@_selectedItem.DaysOfMonth" SelectedValuesChanged="OnSelectedDaysChanged" MultiSelection="true" Clearable="true" SelectAll="true" SelectAllText="Select All Days">
|
|
@foreach (int day in Enumerable.Range(1, 31))
|
|
{
|
|
<MudSelectItem Value="@day">@day</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
|
<div class="d-flex">
|
|
<MudText>Months</MudText>
|
|
</div>
|
|
<MudSelect T="int" SelectedValues="@_selectedItem.MonthsOfYear" SelectedValuesChanged="OnSelectedMonthsChanged" MultiSelection="true" Clearable="true" SelectAll="true" SelectAllText="Select All Months">
|
|
@foreach (int month in Enumerable.Range(1, 12))
|
|
{
|
|
<MudSelectItem Value="@month">@_dtf.GetMonthName(month)</MudSelectItem>
|
|
}
|
|
</MudSelect>
|
|
</MudStack>
|
|
}
|
|
else
|
|
{
|
|
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Preview</MudText>
|
|
<MudDivider Class="mb-6"/>
|
|
<MudCalendar ShowWeek="false"
|
|
ShowDay="false"
|
|
DateRangeChanged="@(range => DateRangeChanged(range))"
|
|
MonthCellMinHeight="115"
|
|
Items="_previewItems"/>
|
|
}
|
|
</MudContainer>
|
|
</div>
|
|
</MudForm>
|
|
|
|
@code {
|
|
private CancellationTokenSource _cts;
|
|
|
|
private readonly DateTimeFormatInfo _dtf = CultureInfo.CurrentUICulture.DateTimeFormat;
|
|
|
|
[Parameter]
|
|
public int Id { get; set; }
|
|
|
|
private readonly List<TemplateGroupViewModel> _templateGroups = [];
|
|
private readonly List<TemplateViewModel> _templates = [];
|
|
|
|
private readonly List<DecoTemplateGroupViewModel> _decoTemplateGroups = [];
|
|
private readonly List<DecoTemplateViewModel> _decoTemplates = [];
|
|
|
|
private string _channelName;
|
|
private List<PlayoutTemplateEditViewModel> _items = [];
|
|
private TemplateGroupViewModel _selectedGroup;
|
|
private DecoTemplateGroupViewModel _selectedDecoTemplateGroup;
|
|
private PlayoutTemplateEditViewModel _selectedItem;
|
|
private readonly List<CalendarItem> _previewItems = [];
|
|
|
|
public void Dispose()
|
|
{
|
|
_cts?.Cancel();
|
|
_cts?.Dispose();
|
|
}
|
|
|
|
protected override async Task OnParametersSetAsync()
|
|
{
|
|
_cts?.Cancel();
|
|
_cts?.Dispose();
|
|
_cts = new CancellationTokenSource();
|
|
var token = _cts.Token;
|
|
|
|
try
|
|
{
|
|
_channelName = (await Mediator.Send(new GetChannelNameByPlayoutId(Id), token)).IfNone(string.Empty);
|
|
|
|
_templateGroups.Clear();
|
|
_templateGroups.AddRange(await Mediator.Send(new GetAllTemplateGroups(), token));
|
|
|
|
_decoTemplateGroups.Clear();
|
|
_decoTemplateGroups.AddRange(await Mediator.Send(new GetAllDecoTemplateGroups(), token));
|
|
|
|
List<PlayoutTemplateViewModel> results = await Mediator.Send(new GetPlayoutTemplates(Id), token);
|
|
_items = results.Map(ProjectToEditViewModel).ToList();
|
|
if (_items.Count == 1)
|
|
{
|
|
await SelectedItemChanged(_items.Head());
|
|
}
|
|
}
|
|
catch (OperationCanceledException)
|
|
{
|
|
// do nothing
|
|
}
|
|
}
|
|
|
|
private PlayoutTemplateEditViewModel ProjectToEditViewModel(PlayoutTemplateViewModel item) =>
|
|
new()
|
|
{
|
|
Id = item.Id,
|
|
Template = item.Template,
|
|
DecoTemplate = item.DecoTemplate,
|
|
Index = item.Index,
|
|
DaysOfWeek = item.DaysOfWeek.ToList(),
|
|
DaysOfMonth = item.DaysOfMonth.ToList(),
|
|
MonthsOfYear = item.MonthsOfYear.ToList(),
|
|
LimitToDateRange = item.LimitToDateRange,
|
|
StartMonth = item.StartMonth,
|
|
StartDay = item.StartDay,
|
|
StartYear = item.StartYear,
|
|
EndMonth = item.EndMonth,
|
|
EndDay = item.EndDay,
|
|
EndYear = item.EndYear
|
|
};
|
|
|
|
private async Task UpdateTemplateGroupItems(TemplateGroupViewModel templateGroup)
|
|
{
|
|
_selectedGroup = templateGroup;
|
|
|
|
_templates.Clear();
|
|
_templates.AddRange(await Mediator.Send(new GetTemplatesByTemplateGroupId(_selectedGroup.Id), _cts.Token));
|
|
}
|
|
|
|
private async Task UpdateDecoTemplateGroupItems(DecoTemplateGroupViewModel decoTemplateGroup)
|
|
{
|
|
_selectedDecoTemplateGroup = decoTemplateGroup;
|
|
|
|
_decoTemplates.Clear();
|
|
_decoTemplates.AddRange(await Mediator.Send(new GetDecoTemplatesByDecoTemplateGroupId(_selectedDecoTemplateGroup.Id), _cts.Token));
|
|
}
|
|
|
|
private async Task SelectedItemChanged(PlayoutTemplateEditViewModel template)
|
|
{
|
|
_selectedItem = template;
|
|
|
|
foreach (TemplateGroupViewModel group in Optional(_templateGroups.Find(group => group.Id == _selectedItem?.Template?.TemplateGroupId)))
|
|
{
|
|
await UpdateTemplateGroupItems(group);
|
|
}
|
|
|
|
foreach (DecoTemplateGroupViewModel group in Optional(_decoTemplateGroups.Find(group => group.Id == _selectedItem?.DecoTemplate?.DecoTemplateGroupId)))
|
|
{
|
|
await UpdateDecoTemplateGroupItems(group);
|
|
}
|
|
}
|
|
|
|
private void SelectWeekdays()
|
|
{
|
|
_selectedItem?.DaysOfWeek.Clear();
|
|
_selectedItem?.DaysOfWeek.AddRange(
|
|
[
|
|
DayOfWeek.Monday,
|
|
DayOfWeek.Tuesday,
|
|
DayOfWeek.Wednesday,
|
|
DayOfWeek.Thursday,
|
|
DayOfWeek.Friday
|
|
]);
|
|
}
|
|
|
|
private void SelectWeekends()
|
|
{
|
|
_selectedItem?.DaysOfWeek.Clear();
|
|
_selectedItem?.DaysOfWeek.AddRange(
|
|
[
|
|
DayOfWeek.Saturday,
|
|
DayOfWeek.Sunday
|
|
]);
|
|
}
|
|
|
|
private void AddTemplate()
|
|
{
|
|
var item = new PlayoutTemplateEditViewModel
|
|
{
|
|
Index = _items.Map(i => i.Index).DefaultIfEmpty().Max() + 1,
|
|
DaysOfWeek = AlternateScheduleSelector.AllDaysOfWeek(),
|
|
DaysOfMonth = AlternateScheduleSelector.AllDaysOfMonth(),
|
|
MonthsOfYear = AlternateScheduleSelector.AllMonthsOfYear()
|
|
};
|
|
|
|
_items.Add(item);
|
|
_selectedItem = item;
|
|
}
|
|
|
|
private void DeleteTemplate(PlayoutTemplateEditViewModel item)
|
|
{
|
|
_selectedItem = null;
|
|
_items.Remove(item);
|
|
}
|
|
|
|
private void MoveItemUp(PlayoutTemplateEditViewModel item)
|
|
{
|
|
// swap with lower index
|
|
PlayoutTemplateEditViewModel toSwap = _items.OrderByDescending(x => x.Index).First(x => x.Index < item.Index);
|
|
(toSwap.Index, item.Index) = (item.Index, toSwap.Index);
|
|
}
|
|
|
|
private void MoveItemDown(PlayoutTemplateEditViewModel item)
|
|
{
|
|
// swap with higher index
|
|
PlayoutTemplateEditViewModel toSwap = _items.OrderBy(x => x.Index).First(x => x.Index > item.Index);
|
|
(toSwap.Index, item.Index) = (item.Index, toSwap.Index);
|
|
}
|
|
|
|
private async Task SaveChanges()
|
|
{
|
|
if (_items.Any(i => i.Template is null))
|
|
{
|
|
Snackbar.Add("Unable to save; item has no template selected", Severity.Error);
|
|
return;
|
|
}
|
|
|
|
var items = _items.Map(item => new ReplacePlayoutTemplate(
|
|
item.Id,
|
|
item.Index,
|
|
item.Template.Id,
|
|
item.DecoTemplate?.Id,
|
|
item.DaysOfWeek,
|
|
item.DaysOfMonth,
|
|
item.MonthsOfYear,
|
|
item.LimitToDateRange,
|
|
item.StartMonth,
|
|
item.StartDay,
|
|
item.StartYear,
|
|
item.EndMonth,
|
|
item.EndDay,
|
|
item.EndYear)).ToList();
|
|
|
|
Option<BaseError> maybeError = await Mediator.Send(new ReplacePlayoutTemplateItems(Id, items), _cts.Token);
|
|
|
|
maybeError.Match(
|
|
error =>
|
|
{
|
|
Snackbar.Add($"Unexpected error saving playout templates: {error.Value}", Severity.Error);
|
|
Logger.LogError("Unexpected error saving playout templates: {Error}", error.Value);
|
|
},
|
|
() => NavigationManager.NavigateTo("playouts"));
|
|
}
|
|
|
|
private async Task PreviewCalendar()
|
|
{
|
|
_selectedItem = null;
|
|
await InvokeAsync(StateHasChanged);
|
|
}
|
|
|
|
private async Task DateRangeChanged(DateRange dateRange)
|
|
{
|
|
await Task.CompletedTask;
|
|
|
|
_previewItems.Clear();
|
|
|
|
var prioritized = _items.Filter(i => i.Template is not null).OrderBy(t => t.Index).ToList();
|
|
|
|
if (dateRange.Start.HasValue && dateRange.End.HasValue)
|
|
{
|
|
DateTime current = dateRange.Start.Value.Date;
|
|
while (current <= dateRange.End.Value.Date)
|
|
{
|
|
foreach (PlayoutTemplateEditViewModel template in prioritized)
|
|
{
|
|
if (template.AppliesToDate(current))
|
|
{
|
|
_previewItems.Add(
|
|
new CalendarItem
|
|
{
|
|
AllDay = true,
|
|
Start = current,
|
|
Text = template.Template.Name
|
|
});
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
current = current.AddDays(1);
|
|
}
|
|
}
|
|
}
|
|
|
|
private string ToDaysOfWeekString(List<DayOfWeek> daysOfWeek)
|
|
{
|
|
if (daysOfWeek.Count is 0 or 7)
|
|
{
|
|
return "*any*";
|
|
}
|
|
|
|
daysOfWeek.Sort();
|
|
|
|
return string.Join(", ", daysOfWeek.Map(_dtf.GetAbbreviatedDayName));
|
|
}
|
|
|
|
private string ToDaysOfMonthString(List<int> daysOfMonth)
|
|
{
|
|
if (daysOfMonth.Count is 0 or 31)
|
|
{
|
|
return "*any*";
|
|
}
|
|
|
|
return ToRangeString(daysOfMonth);
|
|
}
|
|
|
|
private string ToMonthsOfYearString(List<int> monthsOfYear)
|
|
{
|
|
if (monthsOfYear.Count is 0 or 12)
|
|
{
|
|
return "*any*";
|
|
}
|
|
|
|
monthsOfYear.Sort();
|
|
|
|
return string.Join(", ", monthsOfYear.Map(_dtf.GetAbbreviatedMonthName));
|
|
}
|
|
|
|
private static string ToRangeString(List<int> list)
|
|
{
|
|
list = list.Distinct().ToList();
|
|
list.Sort();
|
|
|
|
var result = new StringBuilder();
|
|
for (var i = 0; i < list.Count; i++)
|
|
{
|
|
int temp = list[i];
|
|
|
|
//add a number
|
|
result.Append(list[i]);
|
|
|
|
//skip number(s) between a range
|
|
while (i < list.Count - 1 && list[i + 1] == list[i] + 1)
|
|
{
|
|
i++;
|
|
}
|
|
|
|
//add the range
|
|
if (temp != list[i])
|
|
{
|
|
result.Append("-").Append(list[i]);
|
|
}
|
|
|
|
//add comma
|
|
if (i != list.Count - 1)
|
|
{
|
|
result.Append(", ");
|
|
}
|
|
}
|
|
|
|
return result.ToString();
|
|
}
|
|
|
|
private string SelectedRowClassFunc(PlayoutTemplateEditViewModel element, int rowNumber) => _selectedItem != null && _selectedItem == element ? "selected" : string.Empty;
|
|
|
|
private void OnSelectedDaysChanged(IEnumerable<DayOfWeek> selectedDays)
|
|
{
|
|
_selectedItem.DaysOfWeek.Clear();
|
|
_selectedItem.DaysOfWeek.AddRange(selectedDays);
|
|
}
|
|
|
|
private void OnSelectedDaysChanged(IEnumerable<int> selectedDays)
|
|
{
|
|
_selectedItem.DaysOfMonth.Clear();
|
|
_selectedItem.DaysOfMonth.AddRange(selectedDays);
|
|
}
|
|
|
|
private void OnSelectedMonthsChanged(IEnumerable<int> selectedMonths)
|
|
{
|
|
_selectedItem.MonthsOfYear.Clear();
|
|
_selectedItem.MonthsOfYear.AddRange(selectedMonths);
|
|
}
|
|
|
|
}
|