update layout for group editors (#2140)
* update block group editor * update playlist group editor * update template group editor * update deco group editor * update deco template group editor * update deco editor * update logs layout * update changelog
This commit is contained in:
+68
-69
@@ -6,50 +6,53 @@
|
||||
@inject IMediator Mediator
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Blocks</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mr-4">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<MudTextField Class="mt-3 mx-3" Label="Block Group Name" @bind-Value="_blockGroupName" For="@(() => _blockGroupName)"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddBlockGroup())" Class="ml-4 mb-4">
|
||||
Add Block Group
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mb-6">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<div class="mx-4">
|
||||
<MudSelect Label="Block Group" @bind-Value="_selectedBlockGroup" Class="mt-3">
|
||||
@foreach (BlockGroupViewModel blockGroup in _blockGroups)
|
||||
{
|
||||
<MudSelectItem Value="@blockGroup">@blockGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField Class="mt-3" Label="Block Name" @bind-Value="_blockName" For="@(() => _blockName)"/>
|
||||
</div>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddBlock())" Class="ml-4 mb-4">
|
||||
Add Block
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudCard>
|
||||
<MudTreeView T="BlockTreeItemViewModel" ServerData="LoadServerData" Items="@TreeItems" Hover="true" ExpandOnClick="true">
|
||||
<MudForm Style="max-height: 100%">
|
||||
<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">Block Groups</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>Block Group Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_blockGroupName" For="@(() => _blockGroupName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddBlockGroup())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Block Group
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Blocks</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>Block Group</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_selectedBlockGroup">
|
||||
@foreach (BlockGroupViewModel blockGroup in _blockGroups)
|
||||
{
|
||||
<MudSelectItem Value="@blockGroup">@blockGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Block Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_blockName" For="@(() => _blockName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddBlock())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Block
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex"></div>
|
||||
<MudTreeView T="BlockTreeItemViewModel" Items="@_treeItems" Hover="true" Style="width: 100%">
|
||||
<ItemTemplate Context="item">
|
||||
<MudTreeViewItem T="BlockTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" CanExpand="@item.Value.CanExpand" Value="@item.Value">
|
||||
<MudTreeViewItem T="BlockTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" Value="@item.Value">
|
||||
<BodyContent>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||
<MudGrid Justify="Justify.FlexStart">
|
||||
@@ -75,14 +78,14 @@
|
||||
</MudTreeViewItem>
|
||||
</ItemTemplate>
|
||||
</MudTreeView>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private List<TreeItemData<BlockTreeItemViewModel>> TreeItems { get; set; } = [];
|
||||
private readonly List<TreeItemData<BlockTreeItemViewModel>> _treeItems = [];
|
||||
private List<BlockGroupViewModel> _blockGroups = [];
|
||||
private BlockGroupViewModel _selectedBlockGroup;
|
||||
private string _blockGroupName;
|
||||
@@ -96,14 +99,20 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await ReloadBlockGroups();
|
||||
await ReloadBlockTree();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task ReloadBlockGroups()
|
||||
private async Task ReloadBlockTree()
|
||||
{
|
||||
_blockGroups = await Mediator.Send(new GetAllBlockGroups(), _cts.Token);
|
||||
TreeItems = _blockGroups.Map(g => new TreeItemData<BlockTreeItemViewModel> { Value = new BlockTreeItemViewModel(g) }).ToList();
|
||||
|
||||
_treeItems.Clear();
|
||||
BlockTreeViewModel tree = await Mediator.Send(new GetBlockTree(), _cts.Token);
|
||||
foreach (BlockTreeBlockGroupViewModel group in tree.Groups)
|
||||
{
|
||||
_treeItems.Add(new TreeItemData<BlockTreeItemViewModel> { Value = new BlockTreeItemViewModel(group) });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddBlockGroup()
|
||||
@@ -120,7 +129,7 @@
|
||||
|
||||
foreach (BlockGroupViewModel blockGroup in result.RightToSeq())
|
||||
{
|
||||
TreeItems.Add(new TreeItemData<BlockTreeItemViewModel> { Value = new BlockTreeItemViewModel(blockGroup) });
|
||||
_treeItems.Add(new TreeItemData<BlockTreeItemViewModel> { Value = new BlockTreeItemViewModel(blockGroup) });
|
||||
_blockGroupName = null;
|
||||
|
||||
_blockGroups = await Mediator.Send(new GetAllBlockGroups(), _cts.Token);
|
||||
@@ -143,7 +152,7 @@
|
||||
|
||||
foreach (BlockViewModel block in result.RightToSeq())
|
||||
{
|
||||
foreach (BlockTreeItemViewModel item in TreeItems.Map(i => i.Value).Where(item => item.BlockGroupId == _selectedBlockGroup.Id))
|
||||
foreach (BlockTreeItemViewModel item in _treeItems.Map(i => i.Value).Where(item => item.BlockGroupId == _selectedBlockGroup.Id))
|
||||
{
|
||||
item.TreeItems.Add(new TreeItemData<BlockTreeItemViewModel> { Value = new BlockTreeItemViewModel(block) });
|
||||
}
|
||||
@@ -154,20 +163,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<TreeItemData<BlockTreeItemViewModel>>> LoadServerData(BlockTreeItemViewModel parentNode)
|
||||
{
|
||||
foreach (int blockGroupId in Optional(parentNode.BlockGroupId))
|
||||
{
|
||||
List<BlockViewModel> result = await Mediator.Send(new GetBlocksByBlockGroupId(blockGroupId), _cts.Token);
|
||||
foreach (BlockViewModel block in result)
|
||||
{
|
||||
parentNode.TreeItems.Add(new TreeItemData<BlockTreeItemViewModel> { Value = new BlockTreeItemViewModel(block) });
|
||||
}
|
||||
}
|
||||
|
||||
return parentNode.TreeItems;
|
||||
}
|
||||
|
||||
private async Task DeleteItem(BlockTreeItemViewModel treeItem)
|
||||
{
|
||||
foreach (int blockGroupId in Optional(treeItem.BlockGroupId))
|
||||
@@ -180,7 +175,11 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteBlockGroup(blockGroupId), _cts.Token);
|
||||
TreeItems.RemoveAll(i => i.Value?.BlockGroupId == blockGroupId);
|
||||
_treeItems.RemoveAll(i => i.Value?.BlockGroupId == blockGroupId);
|
||||
if (_selectedBlockGroup?.Id == blockGroupId)
|
||||
{
|
||||
_selectedBlockGroup = null;
|
||||
}
|
||||
|
||||
_blockGroups = await Mediator.Send(new GetAllBlockGroups(), _cts.Token);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -197,7 +196,7 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteBlock(blockId), _cts.Token);
|
||||
foreach (BlockTreeItemViewModel parent in TreeItems.Map(i => i.Value))
|
||||
foreach (BlockTreeItemViewModel parent in _treeItems.Map(i => i.Value))
|
||||
{
|
||||
parent.TreeItems.RemoveAll(i => i.Value == treeItem);
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@
|
||||
<MudTablePager/>
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
<MudText Typo="Typo.h5" Class="mt-6 mb-2">Multi Collections</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Multi Collections</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudTable Hover="true"
|
||||
@bind-RowsPerPage="@_multiCollectionsRowsPerPage"
|
||||
@@ -104,7 +104,7 @@
|
||||
<MudTablePager/>
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
<MudText Typo="Typo.h5" Class="mt-6 mb-2">Smart Collections</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Smart Collections</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudTable Hover="true"
|
||||
@bind-RowsPerPage="@_smartCollectionsRowsPerPage"
|
||||
|
||||
+284
-249
@@ -12,284 +12,319 @@
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IMediator Mediator
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8" Style="display: flex; flex-direction: row">
|
||||
<MudStack Class="mr-6">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Edit Deco</MudText>
|
||||
<MudCard Class="mb-6" Style="width: 350px">
|
||||
<MudCardContent>
|
||||
<MudTextField Label="Name" @bind-Value="_deco.Name" For="@(() => _deco.Name)"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SaveChanges())" StartIcon="@Icons.Material.Filled.Save">
|
||||
Save Changes
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
<MudCard Class="mb-6" Style="width: 350px">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudText Typo="Typo.h6">Watermark</MudText>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudSelect Label="Watermark Mode" @bind-Value="_deco.WatermarkMode" For="@(() => _deco.WatermarkMode)">
|
||||
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||
</MudSelect>
|
||||
<MudSelect Disabled="@(_deco.WatermarkMode != DecoMode.Override)" Label="Watermark Override" @bind-Value="_deco.WatermarkId" For="@(() => _deco.WatermarkId)"
|
||||
Clearable="true">
|
||||
<MudSelectItem T="int?" Value="@((int?)null)">(none)</MudSelectItem>
|
||||
@foreach (WatermarkViewModel watermark in _watermarks)
|
||||
{
|
||||
<MudSelectItem T="int?" Value="@watermark.Id">@watermark.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudSwitch T="bool"
|
||||
Class="mt-3"
|
||||
Disabled="@(_deco.WatermarkMode != DecoMode.Override)"
|
||||
@bind-Value="_deco.UseWatermarkDuringFiller"
|
||||
Color="Color.Primary"
|
||||
Label="Use Watermark During Filler"/>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
<MudCard Class="mb-6" Style="width: 350px">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudTooltip Style="max-width: 350px">
|
||||
<ChildContent>
|
||||
<MudText Typo="Typo.h6" Class="d-flex align-center justify-center">
|
||||
Default Filler
|
||||
|
||||
<MudIcon Icon="@Icons.Material.Filled.Info"/>
|
||||
</MudText>
|
||||
</ChildContent>
|
||||
<TooltipContent>
|
||||
<MudText Typo="Typo.body2">After all blocks have been scheduled, a second pass will be made to fill unscheduled time using random items from this collection.</MudText>
|
||||
</TooltipContent>
|
||||
</MudTooltip>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudSelect Label="Default Filler Mode" @bind-Value="_deco.DefaultFillerMode" For="@(() => _deco.DefaultFillerMode)">
|
||||
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||
</MudSelect>
|
||||
<MudSelect Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Default Filler Collection Type"
|
||||
@bind-Value="_deco.DefaultFillerCollectionType"
|
||||
For="@(() => _deco.DefaultFillerCollectionType)">
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Collection">Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionShow">Television Show</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionSeason">Television Season</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Artist">Artist</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.MultiCollection">Multi Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.SmartCollection">Smart Collection</MudSelectItem>
|
||||
</MudSelect>
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.Collection)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="MediaCollectionViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Collection"
|
||||
@bind-value="_deco.DefaultFillerCollection">
|
||||
@foreach (MediaCollectionViewModel collection in _mediaCollections)
|
||||
<MudForm Style="max-height: 100%">
|
||||
<MudPaper Square="true" Style="display: flex; height: 64px; min-height: 64px; width: 100%; z-index: 100; align-items: center">
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => SaveChanges())" Class="ml-8" StartIcon="@Icons.Material.Filled.Save">
|
||||
Save Changes
|
||||
</MudButton>
|
||||
</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">Deco</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>Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_deco.Name" For="@(() => _deco.Name)"/>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Watermark</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>Watermark Mode</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_deco.WatermarkMode" For="@(() => _deco.WatermarkMode)">
|
||||
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Watermark Override</MudText>
|
||||
</div>
|
||||
<MudSelect Disabled="@(_deco.WatermarkMode != DecoMode.Override)" @bind-Value="_deco.WatermarkId" For="@(() => _deco.WatermarkId)"
|
||||
Clearable="true">
|
||||
<MudSelectItem T="int?" Value="@((int?)null)">(none)</MudSelectItem>
|
||||
@foreach (WatermarkViewModel watermark in _watermarks)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
<MudSelectItem T="int?" Value="@watermark.Id">@watermark.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Use Watermark During Filler</MudText>
|
||||
</div>
|
||||
<MudCheckBox T="bool"
|
||||
Disabled="@(_deco.WatermarkMode != DecoMode.Override)"
|
||||
@bind-Value="_deco.UseWatermarkDuringFiller"
|
||||
Color="Color.Primary"
|
||||
Dense="true" />
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Default Filler</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudText Typo="Typo.body2" Class="mb-6">After all blocks have been scheduled, a second pass will be made to fill unscheduled time using random items from this collection.</MudText>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Default Filler Mode</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_deco.DefaultFillerMode" For="@(() => _deco.DefaultFillerMode)">
|
||||
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Default Filler Collection Type</MudText>
|
||||
</div>
|
||||
<MudSelect Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-Value="_deco.DefaultFillerCollectionType"
|
||||
For="@(() => _deco.DefaultFillerCollectionType)">
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Collection">Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionShow">Television Show</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionSeason">Television Season</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Artist">Artist</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.MultiCollection">Multi Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.SmartCollection">Smart Collection</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.Collection)
|
||||
{
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Collection</MudText>
|
||||
</div>
|
||||
<MudSelect T="MediaCollectionViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DefaultFillerCollection">
|
||||
@foreach (MediaCollectionViewModel collection in _mediaCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.MultiCollection)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="MultiCollectionViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Multi Collection"
|
||||
@bind-value="_deco.DefaultFillerMultiCollection">
|
||||
@foreach (MultiCollectionViewModel collection in _multiCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Multi Collection</MudText>
|
||||
</div>
|
||||
<MudSelect T="MultiCollectionViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DefaultFillerMultiCollection">
|
||||
@foreach (MultiCollectionViewModel collection in _multiCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.SmartCollection)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="SmartCollectionViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Smart Collection"
|
||||
@bind-value="_deco.DefaultFillerSmartCollection">
|
||||
@foreach (SmartCollectionViewModel collection in _smartCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Smart Collection</MudText>
|
||||
</div>
|
||||
<MudSelect T="SmartCollectionViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DefaultFillerSmartCollection">
|
||||
@foreach (SmartCollectionViewModel collection in _smartCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.TelevisionShow)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Television Show"
|
||||
@bind-value="_deco.DefaultFillerMediaItem">
|
||||
@foreach (NamedMediaItemViewModel show in _televisionShows)
|
||||
{
|
||||
<MudSelectItem Value="@show">@show.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Television Show</MudText>
|
||||
</div>
|
||||
<MudSelect T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DefaultFillerMediaItem">
|
||||
@foreach (NamedMediaItemViewModel show in _televisionShows)
|
||||
{
|
||||
<MudSelectItem Value="@show">@show.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.TelevisionSeason)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Television Season"
|
||||
@bind-value="_deco.DefaultFillerMediaItem">
|
||||
@foreach (NamedMediaItemViewModel season in _televisionSeasons)
|
||||
{
|
||||
<MudSelectItem Value="@season">@season.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Television Season</MudText>
|
||||
</div>
|
||||
<MudSelect T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DefaultFillerMediaItem">
|
||||
@foreach (NamedMediaItemViewModel season in _televisionSeasons)
|
||||
{
|
||||
<MudSelectItem Value="@season">@season.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DefaultFillerCollectionType == ProgramScheduleItemCollectionType.Artist)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Artist"
|
||||
@bind-value="_deco.DefaultFillerMediaItem">
|
||||
@foreach (NamedMediaItemViewModel artist in _artists)
|
||||
{
|
||||
<MudSelectItem Value="@artist">@artist.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Artist</MudText>
|
||||
</div>
|
||||
<MudSelect T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DefaultFillerMediaItem">
|
||||
@foreach (NamedMediaItemViewModel artist in _artists)
|
||||
{
|
||||
<MudSelectItem Value="@artist">@artist.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
<MudSwitch T="bool"
|
||||
Class="mt-3"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
Label="Trim To Fit"
|
||||
@bind-Value="_deco.DefaultFillerTrimToFit"
|
||||
Color="Color.Primary"/>
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
<MudCard Class="mb-6" Style="width: 350px">
|
||||
<MudCardHeader>
|
||||
<CardHeaderContent>
|
||||
<MudTooltip Style="max-width: 350px">
|
||||
<ChildContent>
|
||||
<MudText Typo="Typo.h6" Class="d-flex align-center justify-center">
|
||||
Dead Air Fallback
|
||||
|
||||
<MudIcon Icon="@Icons.Material.Filled.Info"/>
|
||||
</MudText>
|
||||
</ChildContent>
|
||||
<TooltipContent>
|
||||
<MudText Typo="Typo.body2">When no playout item is found for the current time, *one* item will be randomly selected from this collection and looped and trimmed to exactly fit until the start of the next playout item.</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mt-3">This replaces the "Channel is Offline" image that would otherwise display.</MudText>
|
||||
</TooltipContent>
|
||||
</MudTooltip>
|
||||
</CardHeaderContent>
|
||||
</MudCardHeader>
|
||||
<MudCardContent>
|
||||
<MudSelect Label="Dead Air Fallback Mode" @bind-Value="_deco.DeadAirFallbackMode" For="@(() => _deco.DeadAirFallbackMode)">
|
||||
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||
</MudSelect>
|
||||
<MudSelect Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Dead Air Fallback Collection Type"
|
||||
@bind-Value="_deco.DeadAirFallbackCollectionType"
|
||||
For="@(() => _deco.DeadAirFallbackCollectionType)">
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Collection">Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionShow">Television Show</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionSeason">Television Season</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Artist">Artist</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.MultiCollection">Multi Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.SmartCollection">Smart Collection</MudSelectItem>
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Trim To Fit</MudText>
|
||||
</div>
|
||||
<MudCheckBox T="bool"
|
||||
Disabled="@(_deco.DefaultFillerMode != DecoMode.Override)"
|
||||
@bind-Value="_deco.DefaultFillerTrimToFit"
|
||||
Color="Color.Primary"
|
||||
Dense="true"/>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Dead Air Fallback</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudText Typo="Typo.body2">When no playout item is found for the current time, *one* item will be randomly selected from this collection and looped and trimmed to exactly fit until the start of the next playout item.</MudText>
|
||||
<MudText Typo="Typo.body2" Class="mb-6 mt-3">This replaces the "Channel is Offline" image that would otherwise display.</MudText>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Dead Air Fallback Mode</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_deco.DeadAirFallbackMode" For="@(() => _deco.DeadAirFallbackMode)">
|
||||
<MudSelectItem Value="DecoMode.Inherit">Inherit</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Disable">Disable</MudSelectItem>
|
||||
<MudSelectItem Value="DecoMode.Override">Override</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Dead Air Fallback Collection Type</MudText>
|
||||
</div>
|
||||
<MudSelect Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-Value="_deco.DeadAirFallbackCollectionType"
|
||||
For="@(() => _deco.DeadAirFallbackCollectionType)">
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Collection">Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionShow">Television Show</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.TelevisionSeason">Television Season</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.Artist">Artist</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.MultiCollection">Multi Collection</MudSelectItem>
|
||||
<MudSelectItem Value="ProgramScheduleItemCollectionType.SmartCollection">Smart Collection</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.Collection)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="MediaCollectionViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Collection"
|
||||
@bind-value="_deco.DeadAirFallbackCollection">
|
||||
@foreach (MediaCollectionViewModel collection in _mediaCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Collection</MudText>
|
||||
</div>
|
||||
<MudSelect T="MediaCollectionViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DeadAirFallbackCollection">
|
||||
@foreach (MediaCollectionViewModel collection in _mediaCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.MultiCollection)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="MultiCollectionViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Multi Collection"
|
||||
@bind-value="_deco.DeadAirFallbackMultiCollection">
|
||||
@foreach (MultiCollectionViewModel collection in _multiCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Multi Collection</MudText>
|
||||
</div>
|
||||
<MudSelect T="MultiCollectionViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DeadAirFallbackMultiCollection">
|
||||
@foreach (MultiCollectionViewModel collection in _multiCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.SmartCollection)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="SmartCollectionViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Smart Collection"
|
||||
@bind-value="_deco.DeadAirFallbackSmartCollection">
|
||||
@foreach (SmartCollectionViewModel collection in _smartCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Smart Collection</MudText>
|
||||
</div>
|
||||
<MudSelect T="SmartCollectionViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DeadAirFallbackSmartCollection">
|
||||
@foreach (SmartCollectionViewModel collection in _smartCollections)
|
||||
{
|
||||
<MudSelectItem Value="@collection">@collection.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.TelevisionShow)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Television Show"
|
||||
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||
@foreach (NamedMediaItemViewModel show in _televisionShows)
|
||||
{
|
||||
<MudSelectItem Value="@show">@show.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Television Show</MudText>
|
||||
</div>
|
||||
<MudSelect T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||
@foreach (NamedMediaItemViewModel show in _televisionShows)
|
||||
{
|
||||
<MudSelectItem Value="@show">@show.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.TelevisionSeason)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Television Season"
|
||||
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||
@foreach (NamedMediaItemViewModel season in _televisionSeasons)
|
||||
{
|
||||
<MudSelectItem Value="@season">@season.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Television Season</MudText>
|
||||
</div>
|
||||
<MudSelect T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||
@foreach (NamedMediaItemViewModel season in _televisionSeasons)
|
||||
{
|
||||
<MudSelectItem Value="@season">@season.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
@if (_deco.DeadAirFallbackCollectionType == ProgramScheduleItemCollectionType.Artist)
|
||||
{
|
||||
<MudSelect Class="mt-3"
|
||||
T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
Label="Artist"
|
||||
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||
@foreach (NamedMediaItemViewModel artist in _artists)
|
||||
{
|
||||
<MudSelectItem Value="@artist">@artist.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Artist</MudText>
|
||||
</div>
|
||||
<MudSelect T="NamedMediaItemViewModel"
|
||||
Disabled="@(_deco.DeadAirFallbackMode != DecoMode.Override)"
|
||||
@bind-value="_deco.DeadAirFallbackMediaItem">
|
||||
@foreach (NamedMediaItemViewModel artist in _artists)
|
||||
{
|
||||
<MudSelectItem Value="@artist">@artist.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
}
|
||||
</MudCardContent>
|
||||
</MudCard>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
@@ -360,34 +395,34 @@
|
||||
DefaultFillerMode = deco.DefaultFillerMode,
|
||||
DefaultFillerCollectionType = deco.DefaultFillerCollectionType,
|
||||
DefaultFillerCollection = deco.DefaultFillerCollectionId.HasValue
|
||||
? _mediaCollections.Find(c => c.Id == deco.DefaultFillerCollectionId.Value)
|
||||
? _mediaCollections.Find(c => c.Id == deco.DefaultFillerCollectionId!.Value)
|
||||
: null,
|
||||
DefaultFillerMediaItem = deco.DefaultFillerMediaItemId.HasValue
|
||||
? _televisionShows.Append(_televisionSeasons).Append(_artists).ToList()
|
||||
.Find(vm => vm.MediaItemId == deco.DefaultFillerMediaItemId.Value)
|
||||
.Find(vm => vm.MediaItemId == deco.DefaultFillerMediaItemId!.Value)
|
||||
: null,
|
||||
DefaultFillerMultiCollection = deco.DefaultFillerMultiCollectionId.HasValue
|
||||
? _multiCollections.Find(c => c.Id == deco.DefaultFillerMultiCollectionId.Value)
|
||||
? _multiCollections.Find(c => c.Id == deco.DefaultFillerMultiCollectionId!.Value)
|
||||
: null,
|
||||
DefaultFillerSmartCollection = deco.DefaultFillerSmartCollectionId.HasValue
|
||||
? _smartCollections.Find(c => c.Id == deco.DefaultFillerSmartCollectionId.Value)
|
||||
? _smartCollections.Find(c => c.Id == deco.DefaultFillerSmartCollectionId!.Value)
|
||||
: null,
|
||||
DefaultFillerTrimToFit = deco.DefaultFillerTrimToFit,
|
||||
|
||||
DeadAirFallbackMode = deco.DeadAirFallbackMode,
|
||||
DeadAirFallbackCollectionType = deco.DeadAirFallbackCollectionType,
|
||||
DeadAirFallbackCollection = deco.DeadAirFallbackCollectionId.HasValue
|
||||
? _mediaCollections.Find(c => c.Id == deco.DeadAirFallbackCollectionId.Value)
|
||||
? _mediaCollections.Find(c => c.Id == deco.DeadAirFallbackCollectionId!.Value)
|
||||
: null,
|
||||
DeadAirFallbackMediaItem = deco.DeadAirFallbackMediaItemId.HasValue
|
||||
? _televisionShows.Append(_televisionSeasons).Append(_artists).ToList()
|
||||
.Find(vm => vm.MediaItemId == deco.DeadAirFallbackMediaItemId.Value)
|
||||
.Find(vm => vm.MediaItemId == deco.DeadAirFallbackMediaItemId!.Value)
|
||||
: null,
|
||||
DeadAirFallbackMultiCollection = deco.DeadAirFallbackMultiCollectionId.HasValue
|
||||
? _multiCollections.Find(c => c.Id == deco.DeadAirFallbackMultiCollectionId.Value)
|
||||
? _multiCollections.Find(c => c.Id == deco.DeadAirFallbackMultiCollectionId!.Value)
|
||||
: null,
|
||||
DeadAirFallbackSmartCollection = deco.DeadAirFallbackSmartCollectionId.HasValue
|
||||
? _smartCollections.Find(c => c.Id == deco.DeadAirFallbackSmartCollectionId.Value)
|
||||
? _smartCollections.Find(c => c.Id == deco.DeadAirFallbackSmartCollectionId!.Value)
|
||||
: null
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,59 +1,63 @@
|
||||
@page "/deco-templates"
|
||||
@using ErsatzTV.Application.Scheduling
|
||||
@using ErsatzTV.Application.Tree
|
||||
@implements IDisposable
|
||||
@inject ILogger<DecoTemplates> Logger
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IMediator Mediator
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Deco Templates</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mr-4">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<MudTextField Class="mt-3 mx-3" Label="Deco Template Group Name" @bind-Value="_decoTemplateGroupName" For="@(() => _decoTemplateGroupName)"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddDecoTemplateGroup())" Class="ml-4 mb-4">
|
||||
Add Deco Template Group
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mb-6">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<div class="mx-4">
|
||||
<MudSelect Label="Deco Template Group" @bind-Value="_selectedDecoTemplateGroup" Class="mt-3">
|
||||
@foreach (DecoTemplateGroupViewModel decoTemplateGroup in _decoTemplateGroups)
|
||||
{
|
||||
<MudSelectItem Value="@decoTemplateGroup">@decoTemplateGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField Class="mt-3" Label="Deco Template Name" @bind-Value="_decoTemplateName" For="@(() => _decoTemplateName)"/>
|
||||
</div>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddDecoTemplate())" Class="ml-4 mb-4">
|
||||
Add Deco Template
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudCard>
|
||||
<MudTreeView T="DecoTemplateTreeItemViewModel" ServerData="LoadServerData" Items="@TreeItems" Hover="true" ExpandOnClick="true">
|
||||
<MudForm Style="max-height: 100%">
|
||||
<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">Deco Template Groups</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>Deco Template Group Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_decoTemplateGroupName" For="@(() => _decoTemplateGroupName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddDecoTemplateGroup())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Deco Template Group
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Deco Templates</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>Deco Template Group</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_selectedDecoTemplateGroup">
|
||||
@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 Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_decoTemplateName" For="@(() => _decoTemplateName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddDecoTemplate())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Deco Template
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex"></div>
|
||||
<MudTreeView T="DecoTemplateTreeItemViewModel" Items="@_treeItems" Hover="true" Style="width: 100%">
|
||||
<ItemTemplate Context="item">
|
||||
<MudTreeViewItem T="DecoTemplateTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" CanExpand="@item.Value.CanExpand" Value="@item.Value">
|
||||
<MudTreeViewItem T="DecoTemplateTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" Value="@item.Value">
|
||||
<BodyContent>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||
<MudGrid Justify="Justify.FlexStart">
|
||||
<MudItem xs="8">
|
||||
<MudItem xs="5">
|
||||
<MudText>@item.Value.Text</MudText>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
@@ -69,14 +73,14 @@
|
||||
</MudTreeViewItem>
|
||||
</ItemTemplate>
|
||||
</MudTreeView>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private List<TreeItemData<DecoTemplateTreeItemViewModel>> TreeItems { get; set; } = [];
|
||||
private readonly List<TreeItemData<DecoTemplateTreeItemViewModel>> _treeItems = [];
|
||||
private List<DecoTemplateGroupViewModel> _decoTemplateGroups = [];
|
||||
private DecoTemplateGroupViewModel _selectedDecoTemplateGroup;
|
||||
private string _decoTemplateGroupName;
|
||||
@@ -90,14 +94,20 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await ReloadDecoTemplateGroups();
|
||||
await ReloadDecoTemplateTree();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task ReloadDecoTemplateGroups()
|
||||
private async Task ReloadDecoTemplateTree()
|
||||
{
|
||||
_decoTemplateGroups = await Mediator.Send(new GetAllDecoTemplateGroups(), _cts.Token);
|
||||
TreeItems = _decoTemplateGroups.Map(g => new TreeItemData<DecoTemplateTreeItemViewModel> { Value = new DecoTemplateTreeItemViewModel(g) }).ToList();
|
||||
|
||||
_treeItems.Clear();
|
||||
TreeViewModel tree = await Mediator.Send(new GetDecoTemplateTree(), _cts.Token);
|
||||
foreach (TreeGroupViewModel group in tree.Groups)
|
||||
{
|
||||
_treeItems.Add(new TreeItemData<DecoTemplateTreeItemViewModel> { Value = new DecoTemplateTreeItemViewModel(group) });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddDecoTemplateGroup()
|
||||
@@ -109,12 +119,12 @@
|
||||
foreach (BaseError error in result.LeftToSeq())
|
||||
{
|
||||
Snackbar.Add(error.Value, Severity.Error);
|
||||
Logger.LogError("Unexpected error adding deco template group: {Error}", error.Value);
|
||||
Logger.LogError("Unexpected error adding decoTemplate group: {Error}", error.Value);
|
||||
}
|
||||
|
||||
foreach (DecoTemplateGroupViewModel decoTemplateGroup in result.RightToSeq())
|
||||
{
|
||||
TreeItems.Add(new TreeItemData<DecoTemplateTreeItemViewModel> { Value = new DecoTemplateTreeItemViewModel(decoTemplateGroup) });
|
||||
_treeItems.Add(new TreeItemData<DecoTemplateTreeItemViewModel> { Value = new DecoTemplateTreeItemViewModel(decoTemplateGroup) });
|
||||
_decoTemplateGroupName = null;
|
||||
|
||||
_decoTemplateGroups = await Mediator.Send(new GetAllDecoTemplateGroups(), _cts.Token);
|
||||
@@ -132,12 +142,12 @@
|
||||
foreach (BaseError error in result.LeftToSeq())
|
||||
{
|
||||
Snackbar.Add(error.Value, Severity.Error);
|
||||
Logger.LogError("Unexpected error adding deco template: {Error}", error.Value);
|
||||
Logger.LogError("Unexpected error adding decoTemplate: {Error}", error.Value);
|
||||
}
|
||||
|
||||
foreach (DecoTemplateViewModel decoTemplate in result.RightToSeq())
|
||||
{
|
||||
foreach (DecoTemplateTreeItemViewModel item in TreeItems.Map(i => i.Value).Where(item => item.DecoTemplateGroupId == _selectedDecoTemplateGroup.Id))
|
||||
foreach (DecoTemplateTreeItemViewModel item in _treeItems.Map(i => i.Value).Where(item => item.DecoTemplateGroupId == _selectedDecoTemplateGroup.Id))
|
||||
{
|
||||
item.TreeItems.Add(new TreeItemData<DecoTemplateTreeItemViewModel> { Value = new DecoTemplateTreeItemViewModel(decoTemplate) });
|
||||
}
|
||||
@@ -148,33 +158,23 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<TreeItemData<DecoTemplateTreeItemViewModel>>> LoadServerData(DecoTemplateTreeItemViewModel parentNode)
|
||||
{
|
||||
foreach (int decoTemplateGroupId in Optional(parentNode.DecoTemplateGroupId))
|
||||
{
|
||||
List<DecoTemplateViewModel> result = await Mediator.Send(new GetDecoTemplatesByDecoTemplateGroupId(decoTemplateGroupId), _cts.Token);
|
||||
foreach (DecoTemplateViewModel decoTemplate in result)
|
||||
{
|
||||
parentNode.TreeItems.Add(new TreeItemData<DecoTemplateTreeItemViewModel> { Value = new DecoTemplateTreeItemViewModel(decoTemplate) });
|
||||
}
|
||||
}
|
||||
|
||||
return parentNode.TreeItems;
|
||||
}
|
||||
|
||||
private async Task DeleteItem(DecoTemplateTreeItemViewModel treeItem)
|
||||
{
|
||||
foreach (int decoTemplateGroupId in Optional(treeItem.DecoTemplateGroupId))
|
||||
{
|
||||
var parameters = new DialogParameters { { "EntityType", "Deco Template group" }, { "EntityName", treeItem.Text } };
|
||||
var parameters = new DialogParameters { { "EntityType", "decoTemplate group" }, { "EntityName", treeItem.Text } };
|
||||
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
|
||||
|
||||
IDialogReference dialog = await Dialog.ShowAsync<DeleteDialog>("Delete Deco Template Group", parameters, options);
|
||||
IDialogReference dialog = await Dialog.ShowAsync<DeleteDialog>("Delete DecoTemplate Group", parameters, options);
|
||||
DialogResult result = await dialog.Result;
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteDecoTemplateGroup(decoTemplateGroupId), _cts.Token);
|
||||
TreeItems.RemoveAll(i => i.Value?.DecoTemplateGroupId == decoTemplateGroupId);
|
||||
_treeItems.RemoveAll(i => i.Value?.DecoTemplateGroupId == decoTemplateGroupId);
|
||||
if (_selectedDecoTemplateGroup?.Id == decoTemplateGroupId)
|
||||
{
|
||||
_selectedDecoTemplateGroup = null;
|
||||
}
|
||||
|
||||
_decoTemplateGroups = await Mediator.Send(new GetAllDecoTemplateGroups(), _cts.Token);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -183,15 +183,15 @@
|
||||
|
||||
foreach (int decoTemplateId in Optional(treeItem.DecoTemplateId))
|
||||
{
|
||||
var parameters = new DialogParameters { { "EntityType", "Deco Template" }, { "EntityName", treeItem.Text } };
|
||||
var parameters = new DialogParameters { { "EntityType", "decoTemplate" }, { "EntityName", treeItem.Text } };
|
||||
var options = new DialogOptions { CloseButton = true, MaxWidth = MaxWidth.ExtraSmall };
|
||||
|
||||
IDialogReference dialog = await Dialog.ShowAsync<DeleteDialog>("Delete Deco Template", parameters, options);
|
||||
IDialogReference dialog = await Dialog.ShowAsync<DeleteDialog>("Delete DecoTemplate", parameters, options);
|
||||
DialogResult result = await dialog.Result;
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteDecoTemplate(decoTemplateId), _cts.Token);
|
||||
foreach (DecoTemplateTreeItemViewModel parent in TreeItems.Map(i => i.Value))
|
||||
foreach (DecoTemplateTreeItemViewModel parent in _treeItems.Map(i => i.Value))
|
||||
{
|
||||
parent.TreeItems.RemoveAll(i => i.Value == treeItem);
|
||||
}
|
||||
|
||||
+70
-76
@@ -1,67 +1,65 @@
|
||||
@page "/decos"
|
||||
@using ErsatzTV.Application.Scheduling
|
||||
@using ErsatzTV.Application.Tree
|
||||
@implements IDisposable
|
||||
@inject ILogger<Decos> Logger
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IMediator Mediator
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Decos</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mr-4">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<MudTextField Class="mt-3 mx-3" Label="Deco Group Name" @bind-Value="_decoGroupName" For="@(() => _decoGroupName)"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddDecoGroup())" Class="ml-4 mb-4">
|
||||
Add Deco Group
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mb-6">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<div class="mx-4">
|
||||
<MudSelect Label="Deco Group" @bind-Value="_selectedDecoGroup" Class="mt-3">
|
||||
@foreach (DecoGroupViewModel decoGroup in _decoGroups)
|
||||
{
|
||||
<MudSelectItem Value="@decoGroup">@decoGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField Class="mt-3" Label="Deco Name" @bind-Value="_decoName" For="@(() => _decoName)"/>
|
||||
</div>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddDeco())" Class="ml-4 mb-4">
|
||||
Add Deco
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudCard>
|
||||
<MudTreeView T="DecoTreeItemViewModel" ServerData="LoadServerData" Items="@TreeItems" Hover="true" ExpandOnClick="true">
|
||||
<MudForm Style="max-height: 100%">
|
||||
<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">Deco Groups</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>Deco Group Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_decoGroupName" For="@(() => _decoGroupName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddDecoGroup())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Deco Group
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Decos</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>Deco Group</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_selectedDecoGroup">
|
||||
@foreach (DecoGroupViewModel decoGroup in _decoGroups)
|
||||
{
|
||||
<MudSelectItem Value="@decoGroup">@decoGroup.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 Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_decoName" For="@(() => _decoName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddDeco())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Deco
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex"></div>
|
||||
<MudTreeView T="DecoTreeItemViewModel" Items="@_treeItems" Hover="true" Style="width: 100%">
|
||||
<ItemTemplate Context="item">
|
||||
<MudTreeViewItem T="DecoTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" CanExpand="@item.Value.CanExpand" Value="@item.Value">
|
||||
<MudTreeViewItem T="DecoTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" Value="@item.Value">
|
||||
<BodyContent>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||
<MudGrid Justify="Justify.FlexStart">
|
||||
<MudItem xs="5">
|
||||
<MudText>@item.Value.Text</MudText>
|
||||
</MudItem>
|
||||
@if (!string.IsNullOrWhiteSpace(item.Value.EndText))
|
||||
{
|
||||
<MudItem xs="6">
|
||||
<MudText>@item.Value.EndText</MudText>
|
||||
</MudItem>
|
||||
}
|
||||
</MudGrid>
|
||||
<div style="justify-self: end;">
|
||||
@foreach (int decoId in Optional(item.Value.DecoId))
|
||||
@@ -75,14 +73,14 @@
|
||||
</MudTreeViewItem>
|
||||
</ItemTemplate>
|
||||
</MudTreeView>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private List<TreeItemData<DecoTreeItemViewModel>> TreeItems { get; set; } = [];
|
||||
private readonly List<TreeItemData<DecoTreeItemViewModel>> _treeItems = [];
|
||||
private List<DecoGroupViewModel> _decoGroups = [];
|
||||
private DecoGroupViewModel _selectedDecoGroup;
|
||||
private string _decoGroupName;
|
||||
@@ -96,14 +94,20 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await ReloadDecoGroups();
|
||||
await ReloadDecoTree();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task ReloadDecoGroups()
|
||||
private async Task ReloadDecoTree()
|
||||
{
|
||||
_decoGroups = await Mediator.Send(new GetAllDecoGroups(), _cts.Token);
|
||||
TreeItems = _decoGroups.Map(g => new TreeItemData<DecoTreeItemViewModel> { Value = new DecoTreeItemViewModel(g) }).ToList();
|
||||
|
||||
_treeItems.Clear();
|
||||
TreeViewModel tree = await Mediator.Send(new GetDecoTree(), _cts.Token);
|
||||
foreach (TreeGroupViewModel group in tree.Groups)
|
||||
{
|
||||
_treeItems.Add(new TreeItemData<DecoTreeItemViewModel> { Value = new DecoTreeItemViewModel(group) });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddDecoGroup()
|
||||
@@ -120,7 +124,7 @@
|
||||
|
||||
foreach (DecoGroupViewModel decoGroup in result.RightToSeq())
|
||||
{
|
||||
TreeItems.Add(new TreeItemData<DecoTreeItemViewModel> { Value = new DecoTreeItemViewModel(decoGroup) });
|
||||
_treeItems.Add(new TreeItemData<DecoTreeItemViewModel> { Value = new DecoTreeItemViewModel(decoGroup) });
|
||||
_decoGroupName = null;
|
||||
|
||||
_decoGroups = await Mediator.Send(new GetAllDecoGroups(), _cts.Token);
|
||||
@@ -143,7 +147,7 @@
|
||||
|
||||
foreach (DecoViewModel deco in result.RightToSeq())
|
||||
{
|
||||
foreach (DecoTreeItemViewModel item in TreeItems.Where(item => item.Value!.DecoGroupId == _selectedDecoGroup.Id).Map(i => i.Value))
|
||||
foreach (DecoTreeItemViewModel item in _treeItems.Map(i => i.Value).Where(item => item.DecoGroupId == _selectedDecoGroup.Id))
|
||||
{
|
||||
item.TreeItems.Add(new TreeItemData<DecoTreeItemViewModel> { Value = new DecoTreeItemViewModel(deco) });
|
||||
}
|
||||
@@ -154,20 +158,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<TreeItemData<DecoTreeItemViewModel>>> LoadServerData(DecoTreeItemViewModel parentNode)
|
||||
{
|
||||
foreach (int decoGroupId in Optional(parentNode.DecoGroupId))
|
||||
{
|
||||
List<DecoViewModel> result = await Mediator.Send(new GetDecosByDecoGroupId(decoGroupId), _cts.Token);
|
||||
foreach (DecoViewModel deco in result)
|
||||
{
|
||||
parentNode.TreeItems.Add(new TreeItemData<DecoTreeItemViewModel> { Value = new DecoTreeItemViewModel(deco) });
|
||||
}
|
||||
}
|
||||
|
||||
return parentNode.TreeItems;
|
||||
}
|
||||
|
||||
private async Task DeleteItem(DecoTreeItemViewModel treeItem)
|
||||
{
|
||||
foreach (int decoGroupId in Optional(treeItem.DecoGroupId))
|
||||
@@ -180,7 +170,11 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteDecoGroup(decoGroupId), _cts.Token);
|
||||
TreeItems.RemoveAll(i => i.Value?.DecoGroupId == decoGroupId);
|
||||
_treeItems.RemoveAll(i => i.Value?.DecoGroupId == decoGroupId);
|
||||
if (_selectedDecoGroup?.Id == decoGroupId)
|
||||
{
|
||||
_selectedDecoGroup = null;
|
||||
}
|
||||
|
||||
_decoGroups = await Mediator.Send(new GetAllDecoGroups(), _cts.Token);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -197,9 +191,9 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteDeco(decoId), _cts.Token);
|
||||
foreach (DecoTreeItemViewModel parent in TreeItems.Map(i => i.Value))
|
||||
foreach (DecoTreeItemViewModel parent in _treeItems.Map(i => i.Value))
|
||||
{
|
||||
parent.TreeItems.RemoveAll(ti => ti.Value == treeItem);
|
||||
parent.TreeItems.RemoveAll(i => i.Value == treeItem);
|
||||
}
|
||||
|
||||
await InvokeAsync(StateHasChanged);
|
||||
|
||||
@@ -59,7 +59,7 @@
|
||||
<MudSelectItem Value="@ScalingBehavior.Crop">Crop</MudSelectItem>
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mb-2">Video</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Video</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
@@ -220,7 +220,7 @@
|
||||
</div>
|
||||
<MudCheckBox @bind-Value="@_model.DeinterlaceVideo" For="@(() => _model.DeinterlaceVideo)" Dense="true"/>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mb-2">Audio</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Audio</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
|
||||
+52
-42
@@ -1,55 +1,65 @@
|
||||
@page "/system/logs"
|
||||
@using System.Globalization
|
||||
@using ErsatzTV.Application.Configuration
|
||||
@using ErsatzTV.Application.Logs
|
||||
@implements IDisposable
|
||||
@inject IMediator Mediator
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
||||
<MudTable FixedHeader="true"
|
||||
@bind-RowsPerPage="@_rowsPerPage"
|
||||
ServerData="@(new Func<TableState, CancellationToken, Task<TableData<LogEntryViewModel>>>(ServerReload))"
|
||||
Dense="true"
|
||||
@ref="_table">
|
||||
<ToolBarContent>
|
||||
<MudText Typo="Typo.h6">Logs</MudText>
|
||||
<MudSpacer/>
|
||||
<MudTextField T="string" ValueChanged="@(s => OnSearch(s))" Placeholder="Search" Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" Class="mt-0">
|
||||
</MudTextField>
|
||||
</ToolBarContent>
|
||||
<HeaderContent>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="LogEntryViewModel" SortLabel="Timestamp">
|
||||
Timestamp
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="LogEntryViewModel" SortLabel="Level">
|
||||
Level
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>Message</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd DataLabel="Timestamp">@context.Timestamp</MudTd>
|
||||
<MudTd DataLabel="Level">@context.Level</MudTd>
|
||||
<MudTd DataLabel="Message">@context.Message</MudTd>
|
||||
</RowTemplate>
|
||||
<NoRecordsContent>
|
||||
<MudText>No matching records found</MudText>
|
||||
</NoRecordsContent>
|
||||
<LoadingContent>
|
||||
<MudText>Loading...</MudText>
|
||||
</LoadingContent>
|
||||
<PagerContent>
|
||||
<MudTablePager/>
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
</MudContainer>
|
||||
<MudForm Style="max-height: 100%">
|
||||
<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">Logs</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>Search</MudText>
|
||||
</div>
|
||||
<MudTextField T="string" ValueChanged="@(s => OnSearch(s))" Adornment="Adornment.Start"
|
||||
AdornmentIcon="@Icons.Material.Filled.Search" IconSize="Size.Medium" />
|
||||
</MudStack>
|
||||
<MudTable FixedHeader="true"
|
||||
@bind-RowsPerPage="@_rowsPerPage"
|
||||
ServerData="@(new Func<TableState, CancellationToken, Task<TableData<LogEntryViewModel>>>(ServerReload))"
|
||||
Dense="true"
|
||||
Class="mt-10"
|
||||
@ref="_table">
|
||||
<HeaderContent>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="LogEntryViewModel" SortLabel="Timestamp">
|
||||
Timestamp
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>
|
||||
<MudTableSortLabel T="LogEntryViewModel" SortLabel="Level">
|
||||
Level
|
||||
</MudTableSortLabel>
|
||||
</MudTh>
|
||||
<MudTh>Message</MudTh>
|
||||
</HeaderContent>
|
||||
<RowTemplate>
|
||||
<MudTd>@context.Timestamp.ToString("G", _dtf)</MudTd>
|
||||
<MudTd>@context.Level</MudTd>
|
||||
<MudTd>@context.Message</MudTd>
|
||||
</RowTemplate>
|
||||
<NoRecordsContent>
|
||||
<MudText>No matching records found</MudText>
|
||||
</NoRecordsContent>
|
||||
<LoadingContent>
|
||||
<MudText>Loading...</MudText>
|
||||
</LoadingContent>
|
||||
<PagerContent>
|
||||
<MudTablePager/>
|
||||
</PagerContent>
|
||||
</MudTable>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
|
||||
private readonly DateTimeFormatInfo _dtf = CultureInfo.CurrentUICulture.DateTimeFormat;
|
||||
|
||||
private MudTable<LogEntryViewModel> _table;
|
||||
private int _rowsPerPage = 10;
|
||||
private string _searchString;
|
||||
|
||||
@@ -1,55 +1,59 @@
|
||||
@page "/media/playlists"
|
||||
@using ErsatzTV.Application.MediaCollections
|
||||
@using ErsatzTV.Application.Tree
|
||||
@implements IDisposable
|
||||
@inject ILogger<Playlists> Logger
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IMediator Mediator
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Playlists</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mr-4">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<MudTextField Class="mt-3 mx-3" Label="Playlist Group Name" @bind-Value="_playlistGroupName" For="@(() => _playlistGroupName)"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddPlaylistGroup())" Class="ml-4 mb-4">
|
||||
Add Playlist Group
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mb-6">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<div class="mx-4">
|
||||
<MudSelect Label="Playlist Group" @bind-Value="_selectedPlaylistGroup" Class="mt-3">
|
||||
@foreach (PlaylistGroupViewModel playlistGroup in _playlistGroups)
|
||||
{
|
||||
<MudSelectItem Value="@playlistGroup">@playlistGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField Class="mt-3" Label="Playlist Name" @bind-Value="_playlistName" For="@(() => _playlistName)"/>
|
||||
</div>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddPlaylist())" Class="ml-4 mb-4">
|
||||
Add Playlist
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudCard>
|
||||
<MudTreeView T="PlaylistTreeItemViewModel" ServerData="LoadServerData" Items="@TreeItems" Hover="true" ExpandOnClick="true">
|
||||
<MudForm Style="max-height: 100%">
|
||||
<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">Playlist Groups</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>Playlist Group Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_playlistGroupName" For="@(() => _playlistGroupName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddPlaylistGroup())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Playlist Group
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Playlists</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>Playlist Group</MudText>
|
||||
</div>
|
||||
<MudSelect @bind-Value="_selectedPlaylistGroup">
|
||||
@foreach (PlaylistGroupViewModel playlistGroup in _playlistGroups)
|
||||
{
|
||||
<MudSelectItem Value="@playlistGroup">@playlistGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex">
|
||||
<MudText>Playlist Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_playlistName" For="@(() => _playlistName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddPlaylist())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Playlist
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex"></div>
|
||||
<MudTreeView T="PlaylistTreeItemViewModel" Items="@_treeItems" Hover="true" Style="width: 100%">
|
||||
<ItemTemplate Context="item">
|
||||
<MudTreeViewItem T="PlaylistTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" CanExpand="@item.Value.CanExpand" Value="@item.Value">
|
||||
<MudTreeViewItem T="PlaylistTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" Value="@item.Value">
|
||||
<BodyContent>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||
<MudGrid Justify="Justify.FlexStart">
|
||||
@@ -75,14 +79,14 @@
|
||||
</MudTreeViewItem>
|
||||
</ItemTemplate>
|
||||
</MudTreeView>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private List<TreeItemData<PlaylistTreeItemViewModel>> TreeItems { get; set; } = [];
|
||||
private readonly List<TreeItemData<PlaylistTreeItemViewModel>> _treeItems = [];
|
||||
private List<PlaylistGroupViewModel> _playlistGroups = [];
|
||||
private PlaylistGroupViewModel _selectedPlaylistGroup;
|
||||
private string _playlistGroupName;
|
||||
@@ -96,14 +100,20 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await ReloadPlaylistGroups();
|
||||
await ReloadPlaylistTree();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task ReloadPlaylistGroups()
|
||||
private async Task ReloadPlaylistTree()
|
||||
{
|
||||
_playlistGroups = await Mediator.Send(new GetAllPlaylistGroups(), _cts.Token);
|
||||
TreeItems = _playlistGroups.Map(g => new TreeItemData<PlaylistTreeItemViewModel> { Value = new PlaylistTreeItemViewModel(g) }).ToList();
|
||||
|
||||
_treeItems.Clear();
|
||||
TreeViewModel tree = await Mediator.Send(new GetPlaylistTree(), _cts.Token);
|
||||
foreach (TreeGroupViewModel group in tree.Groups)
|
||||
{
|
||||
_treeItems.Add(new TreeItemData<PlaylistTreeItemViewModel> { Value = new PlaylistTreeItemViewModel(group) });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddPlaylistGroup()
|
||||
@@ -120,7 +130,7 @@
|
||||
|
||||
foreach (PlaylistGroupViewModel playlistGroup in result.RightToSeq())
|
||||
{
|
||||
TreeItems.Add(new TreeItemData<PlaylistTreeItemViewModel> { Value = new PlaylistTreeItemViewModel(playlistGroup) });
|
||||
_treeItems.Add(new TreeItemData<PlaylistTreeItemViewModel> { Value = new PlaylistTreeItemViewModel(playlistGroup) });
|
||||
_playlistGroupName = null;
|
||||
|
||||
_playlistGroups = await Mediator.Send(new GetAllPlaylistGroups(), _cts.Token);
|
||||
@@ -143,7 +153,7 @@
|
||||
|
||||
foreach (PlaylistViewModel playlist in result.RightToSeq())
|
||||
{
|
||||
foreach (PlaylistTreeItemViewModel item in TreeItems.Map(i => i.Value).Where(item => item.PlaylistGroupId == _selectedPlaylistGroup.Id))
|
||||
foreach (PlaylistTreeItemViewModel item in _treeItems.Map(i => i.Value).Where(item => item.PlaylistGroupId == _selectedPlaylistGroup.Id))
|
||||
{
|
||||
item.TreeItems.Add(new TreeItemData<PlaylistTreeItemViewModel> { Value = new PlaylistTreeItemViewModel(playlist) });
|
||||
}
|
||||
@@ -154,20 +164,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<TreeItemData<PlaylistTreeItemViewModel>>> LoadServerData(PlaylistTreeItemViewModel parentNode)
|
||||
{
|
||||
foreach (int playlistGroupId in Optional(parentNode.PlaylistGroupId))
|
||||
{
|
||||
List<PlaylistViewModel> result = await Mediator.Send(new GetPlaylistsByPlaylistGroupId(playlistGroupId), _cts.Token);
|
||||
foreach (PlaylistViewModel playlist in result)
|
||||
{
|
||||
parentNode.TreeItems.Add(new TreeItemData<PlaylistTreeItemViewModel> { Value = new PlaylistTreeItemViewModel(playlist) });
|
||||
}
|
||||
}
|
||||
|
||||
return parentNode.TreeItems;
|
||||
}
|
||||
|
||||
private async Task DeleteItem(PlaylistTreeItemViewModel treeItem)
|
||||
{
|
||||
foreach (int playlistGroupId in Optional(treeItem.PlaylistGroupId))
|
||||
@@ -180,7 +176,11 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeletePlaylistGroup(playlistGroupId), _cts.Token);
|
||||
TreeItems.RemoveAll(i => i.Value?.PlaylistGroupId == playlistGroupId);
|
||||
_treeItems.RemoveAll(i => i.Value?.PlaylistGroupId == playlistGroupId);
|
||||
if (_selectedPlaylistGroup?.Id == playlistGroupId)
|
||||
{
|
||||
_selectedPlaylistGroup = null;
|
||||
}
|
||||
|
||||
_playlistGroups = await Mediator.Send(new GetAllPlaylistGroups(), _cts.Token);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -197,7 +197,7 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeletePlaylist(playlistId), _cts.Token);
|
||||
foreach (PlaylistTreeItemViewModel parent in TreeItems.Map(i => i.Value))
|
||||
foreach (PlaylistTreeItemViewModel parent in _treeItems.Map(i => i.Value))
|
||||
{
|
||||
parent.TreeItems.RemoveAll(i => i.Value == treeItem);
|
||||
}
|
||||
|
||||
@@ -202,7 +202,7 @@
|
||||
</MudTable>
|
||||
@if (_selectedPlayoutId != null)
|
||||
{
|
||||
<MudText Typo="Typo.h5" Class="mt-6 mb-2">Playout Detail</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Playout Detail</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudTable Hover="true"
|
||||
Dense="true"
|
||||
|
||||
@@ -1,59 +1,63 @@
|
||||
@page "/templates"
|
||||
@using ErsatzTV.Application.Scheduling
|
||||
@using ErsatzTV.Application.Tree
|
||||
@implements IDisposable
|
||||
@inject ILogger<Templates> Logger
|
||||
@inject ISnackbar Snackbar
|
||||
@inject IMediator Mediator
|
||||
@inject IDialogService Dialog
|
||||
|
||||
<MudContainer MaxWidth="MaxWidth.ExtraLarge" Class="pt-8">
|
||||
<MudText Typo="Typo.h4" Class="mb-4">Templates</MudText>
|
||||
<MudGrid>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mr-4">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<MudTextField Class="mt-3 mx-3" Label="Template Group Name" @bind-Value="_templateGroupName" For="@(() => _templateGroupName)"/>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddTemplateGroup())" Class="ml-4 mb-4">
|
||||
Add Template Group
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="4">
|
||||
<div style="max-width: 400px;" class="mb-6">
|
||||
<MudCard>
|
||||
<MudCardContent>
|
||||
<div class="mx-4">
|
||||
<MudSelect Label="Template Group" @bind-Value="_selectedTemplateGroup" Class="mt-3">
|
||||
@foreach (TemplateGroupViewModel templateGroup in _templateGroups)
|
||||
{
|
||||
<MudSelectItem Value="@templateGroup">@templateGroup.Name</MudSelectItem>
|
||||
}
|
||||
</MudSelect>
|
||||
<MudTextField Class="mt-3" Label="Template Name" @bind-Value="_templateName" For="@(() => _templateName)"/>
|
||||
</div>
|
||||
</MudCardContent>
|
||||
<MudCardActions>
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => AddTemplate())" Class="ml-4 mb-4">
|
||||
Add Template
|
||||
</MudButton>
|
||||
</MudCardActions>
|
||||
</MudCard>
|
||||
</div>
|
||||
</MudItem>
|
||||
<MudItem xs="8">
|
||||
<MudCard>
|
||||
<MudTreeView T="TemplateTreeItemViewModel" ServerData="LoadServerData" Items="@TreeItems" Hover="true" ExpandOnClick="true">
|
||||
<MudForm Style="max-height: 100%">
|
||||
<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">Template Groups</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 Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_templateGroupName" For="@(() => _templateGroupName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddTemplateGroup())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Template Group
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Templates</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 @bind-Value="_selectedTemplateGroup">
|
||||
@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 Name</MudText>
|
||||
</div>
|
||||
<MudTextField @bind-Value="_templateName" For="@(() => _templateName)"/>
|
||||
</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.Primary" OnClick="@(_ => AddTemplate())" StartIcon="@Icons.Material.Filled.Add">
|
||||
Add Template
|
||||
</MudButton>
|
||||
</MudStack>
|
||||
<MudStack Row="true" Breakpoint="Breakpoint.SmAndDown" Class="form-field-stack gap-md-8 mb-5">
|
||||
<div class="d-flex"></div>
|
||||
<MudTreeView T="TemplateTreeItemViewModel" Items="@_treeItems" Hover="true" Style="width: 100%">
|
||||
<ItemTemplate Context="item">
|
||||
<MudTreeViewItem T="TemplateTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" CanExpand="@item.Value.CanExpand" Value="@item.Value">
|
||||
<MudTreeViewItem T="TemplateTreeItemViewModel" Items="@item.Value!.TreeItems" Icon="@item.Value.Icon" Value="@item.Value">
|
||||
<BodyContent>
|
||||
<div style="display: grid; grid-template-columns: 1fr auto; align-items: center; width: 100%">
|
||||
<MudGrid Justify="Justify.FlexStart">
|
||||
<MudItem xs="8">
|
||||
<MudItem xs="5">
|
||||
<MudText>@item.Value.Text</MudText>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
@@ -69,14 +73,14 @@
|
||||
</MudTreeViewItem>
|
||||
</ItemTemplate>
|
||||
</MudTreeView>
|
||||
</MudCard>
|
||||
</MudItem>
|
||||
</MudGrid>
|
||||
</MudContainer>
|
||||
</MudStack>
|
||||
</MudContainer>
|
||||
</div>
|
||||
</MudForm>
|
||||
|
||||
@code {
|
||||
private readonly CancellationTokenSource _cts = new();
|
||||
private List<TreeItemData<TemplateTreeItemViewModel>> TreeItems { get; set; } = [];
|
||||
private readonly List<TreeItemData<TemplateTreeItemViewModel>> _treeItems = [];
|
||||
private List<TemplateGroupViewModel> _templateGroups = [];
|
||||
private TemplateGroupViewModel _selectedTemplateGroup;
|
||||
private string _templateGroupName;
|
||||
@@ -90,14 +94,20 @@
|
||||
|
||||
protected override async Task OnParametersSetAsync()
|
||||
{
|
||||
await ReloadTemplateGroups();
|
||||
await ReloadTemplateTree();
|
||||
await InvokeAsync(StateHasChanged);
|
||||
}
|
||||
|
||||
private async Task ReloadTemplateGroups()
|
||||
private async Task ReloadTemplateTree()
|
||||
{
|
||||
_templateGroups = await Mediator.Send(new GetAllTemplateGroups(), _cts.Token);
|
||||
TreeItems = _templateGroups.Map(g => new TreeItemData<TemplateTreeItemViewModel> { Value = new TemplateTreeItemViewModel(g) }).ToList();
|
||||
|
||||
_treeItems.Clear();
|
||||
TreeViewModel tree = await Mediator.Send(new GetTemplateTree(), _cts.Token);
|
||||
foreach (TreeGroupViewModel group in tree.Groups)
|
||||
{
|
||||
_treeItems.Add(new TreeItemData<TemplateTreeItemViewModel> { Value = new TemplateTreeItemViewModel(group) });
|
||||
}
|
||||
}
|
||||
|
||||
private async Task AddTemplateGroup()
|
||||
@@ -114,7 +124,7 @@
|
||||
|
||||
foreach (TemplateGroupViewModel templateGroup in result.RightToSeq())
|
||||
{
|
||||
TreeItems.Add(new TreeItemData<TemplateTreeItemViewModel> { Value = new TemplateTreeItemViewModel(templateGroup) });
|
||||
_treeItems.Add(new TreeItemData<TemplateTreeItemViewModel> { Value = new TemplateTreeItemViewModel(templateGroup) });
|
||||
_templateGroupName = null;
|
||||
|
||||
_templateGroups = await Mediator.Send(new GetAllTemplateGroups(), _cts.Token);
|
||||
@@ -137,7 +147,7 @@
|
||||
|
||||
foreach (TemplateViewModel template in result.RightToSeq())
|
||||
{
|
||||
foreach (TemplateTreeItemViewModel item in TreeItems.Map(i => i.Value).Where(item => item.TemplateGroupId == _selectedTemplateGroup.Id))
|
||||
foreach (TemplateTreeItemViewModel item in _treeItems.Map(i => i.Value).Where(item => item.TemplateGroupId == _selectedTemplateGroup.Id))
|
||||
{
|
||||
item.TreeItems.Add(new TreeItemData<TemplateTreeItemViewModel> { Value = new TemplateTreeItemViewModel(template) });
|
||||
}
|
||||
@@ -148,20 +158,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<IReadOnlyCollection<TreeItemData<TemplateTreeItemViewModel>>> LoadServerData(TemplateTreeItemViewModel parentNode)
|
||||
{
|
||||
foreach (int templateGroupId in Optional(parentNode.TemplateGroupId))
|
||||
{
|
||||
List<TemplateViewModel> result = await Mediator.Send(new GetTemplatesByTemplateGroupId(templateGroupId), _cts.Token);
|
||||
foreach (TemplateViewModel template in result)
|
||||
{
|
||||
parentNode.TreeItems.Add(new TreeItemData<TemplateTreeItemViewModel> { Value = new TemplateTreeItemViewModel(template) });
|
||||
}
|
||||
}
|
||||
|
||||
return parentNode.TreeItems;
|
||||
}
|
||||
|
||||
private async Task DeleteItem(TemplateTreeItemViewModel treeItem)
|
||||
{
|
||||
foreach (int templateGroupId in Optional(treeItem.TemplateGroupId))
|
||||
@@ -174,7 +170,11 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteTemplateGroup(templateGroupId), _cts.Token);
|
||||
TreeItems.RemoveAll(i => i.Value?.TemplateGroupId == templateGroupId);
|
||||
_treeItems.RemoveAll(i => i.Value?.TemplateGroupId == templateGroupId);
|
||||
if (_selectedTemplateGroup?.Id == templateGroupId)
|
||||
{
|
||||
_selectedTemplateGroup = null;
|
||||
}
|
||||
|
||||
_templateGroups = await Mediator.Send(new GetAllTemplateGroups(), _cts.Token);
|
||||
await InvokeAsync(StateHasChanged);
|
||||
@@ -191,7 +191,7 @@
|
||||
if (result is not null && !result.Canceled)
|
||||
{
|
||||
await Mediator.Send(new DeleteTemplate(templateId), _cts.Token);
|
||||
foreach (TemplateTreeItemViewModel parent in TreeItems.Map(i => i.Value))
|
||||
foreach (TemplateTreeItemViewModel parent in _treeItems.Map(i => i.Value))
|
||||
{
|
||||
parent.TreeItems.RemoveAll(i => i.Value == treeItem);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
<MudButton Disabled="@EntityLocker.IsPlayoutLocked(Id)" Variant="Variant.Filled" Color="Color.Primary" OnClick="@(_ => EditYamlFile())">
|
||||
Edit YAML File
|
||||
</MudButton>
|
||||
<MudText Typo="Typo.h5" Class="mt-6 mb-2">Playout Items and History</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Playout Items and History</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
<MudButton Disabled="@EntityLocker.IsPlayoutLocked(Id)" Variant="Variant.Filled" Color="Color.Error" OnClick="@(_ => EraseItems(eraseHistory: true))">
|
||||
Erase Items and History
|
||||
|
||||
@@ -51,7 +51,7 @@
|
||||
<MudButton Variant="Variant.Filled" Color="Color.Default" OnClick="@(_ => AddPathReplacement())" Class="mt-4">
|
||||
Add Path Replacement
|
||||
</MudButton>
|
||||
<MudText Typo="Typo.h5" Class="mt-6 mb-2">Path Replacement</MudText>
|
||||
<MudText Typo="Typo.h5" Class="mt-10 mb-2">Path Replacement</MudText>
|
||||
<MudDivider Class="mb-6"/>
|
||||
@if (_selectedItem is not null)
|
||||
{
|
||||
|
||||
@@ -10,7 +10,16 @@ public class BlockTreeItemViewModel
|
||||
Text = blockGroup.Name;
|
||||
EndText = string.Empty;
|
||||
TreeItems = [];
|
||||
CanExpand = blockGroup.BlockCount > 0;
|
||||
BlockGroupId = blockGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
|
||||
public BlockTreeItemViewModel(BlockTreeBlockGroupViewModel blockGroup)
|
||||
{
|
||||
Text = blockGroup.Name;
|
||||
EndText = string.Empty;
|
||||
TreeItems = blockGroup.Blocks.Map(b => new TreeItemData<BlockTreeItemViewModel>
|
||||
{ Value = new BlockTreeItemViewModel(b) }).ToList();
|
||||
BlockGroupId = blockGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
@@ -37,6 +46,28 @@ public class BlockTreeItemViewModel
|
||||
BlockId = block.Id;
|
||||
}
|
||||
|
||||
public BlockTreeItemViewModel(BlockTreeBlockViewModel block)
|
||||
{
|
||||
Text = block.Name;
|
||||
if (block.Minutes / 60 >= 1)
|
||||
{
|
||||
string plural = block.Minutes / 60 >= 2 ? "s" : string.Empty;
|
||||
EndText = $"{block.Minutes / 60} hour{plural}";
|
||||
if (block.Minutes % 60 != 0)
|
||||
{
|
||||
EndText += $", {block.Minutes % 60} minutes";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EndText = $"{block.Minutes} minutes";
|
||||
}
|
||||
|
||||
TreeItems = [];
|
||||
CanExpand = false;
|
||||
BlockId = block.Id;
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
|
||||
public string EndText { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ErsatzTV.Application.Scheduling;
|
||||
using ErsatzTV.Application.Tree;
|
||||
using MudBlazor;
|
||||
|
||||
namespace ErsatzTV.ViewModels;
|
||||
@@ -9,7 +10,15 @@ public class DecoTemplateTreeItemViewModel
|
||||
{
|
||||
Text = decoTemplateGroup.Name;
|
||||
TreeItems = [];
|
||||
CanExpand = decoTemplateGroup.DecoTemplateCount > 0;
|
||||
DecoTemplateGroupId = decoTemplateGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
|
||||
public DecoTemplateTreeItemViewModel(TreeGroupViewModel decoTemplateGroup)
|
||||
{
|
||||
Text = decoTemplateGroup.Name;
|
||||
TreeItems = decoTemplateGroup.Children.Map(d => new TreeItemData<DecoTemplateTreeItemViewModel>
|
||||
{ Value = new DecoTemplateTreeItemViewModel(d) }).ToList();
|
||||
DecoTemplateGroupId = decoTemplateGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
@@ -22,6 +31,14 @@ public class DecoTemplateTreeItemViewModel
|
||||
DecoTemplateId = decoTemplate.Id;
|
||||
}
|
||||
|
||||
public DecoTemplateTreeItemViewModel(TreeItemViewModel decoTemplate)
|
||||
{
|
||||
Text = decoTemplate.Name;
|
||||
TreeItems = [];
|
||||
CanExpand = false;
|
||||
DecoTemplateId = decoTemplate.Id;
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
|
||||
public string Icon { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ErsatzTV.Application.Scheduling;
|
||||
using ErsatzTV.Application.Tree;
|
||||
using MudBlazor;
|
||||
|
||||
namespace ErsatzTV.ViewModels;
|
||||
@@ -10,7 +11,15 @@ public class DecoTreeItemViewModel
|
||||
Text = decoGroup.Name;
|
||||
EndText = string.Empty;
|
||||
TreeItems = [];
|
||||
CanExpand = decoGroup.DecoCount > 0;
|
||||
DecoGroupId = decoGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
|
||||
public DecoTreeItemViewModel(TreeGroupViewModel decoGroup)
|
||||
{
|
||||
Text = decoGroup.Name;
|
||||
TreeItems = decoGroup.Children.Map(d => new TreeItemData<DecoTreeItemViewModel>
|
||||
{ Value = new DecoTreeItemViewModel(d) }).ToList();
|
||||
DecoGroupId = decoGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
@@ -23,6 +32,14 @@ public class DecoTreeItemViewModel
|
||||
DecoId = deco.Id;
|
||||
}
|
||||
|
||||
public DecoTreeItemViewModel(TreeItemViewModel deco)
|
||||
{
|
||||
Text = deco.Name;
|
||||
TreeItems = [];
|
||||
CanExpand = false;
|
||||
DecoId = deco.Id;
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
|
||||
public string EndText { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ErsatzTV.Application.MediaCollections;
|
||||
using ErsatzTV.Application.Tree;
|
||||
using MudBlazor;
|
||||
|
||||
namespace ErsatzTV.ViewModels;
|
||||
@@ -10,7 +11,16 @@ public class PlaylistTreeItemViewModel
|
||||
Text = playlistGroup.Name;
|
||||
EndText = string.Empty;
|
||||
TreeItems = [];
|
||||
CanExpand = playlistGroup.PlaylistCount > 0;
|
||||
PlaylistGroupId = playlistGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
|
||||
public PlaylistTreeItemViewModel(TreeGroupViewModel playlistGroup)
|
||||
{
|
||||
Text = playlistGroup.Name;
|
||||
EndText = string.Empty;
|
||||
TreeItems = playlistGroup.Children.Map(p => new TreeItemData<PlaylistTreeItemViewModel>
|
||||
{ Value = new PlaylistTreeItemViewModel(p) }).ToList();
|
||||
PlaylistGroupId = playlistGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
@@ -23,6 +33,14 @@ public class PlaylistTreeItemViewModel
|
||||
PlaylistId = playlist.Id;
|
||||
}
|
||||
|
||||
public PlaylistTreeItemViewModel(TreeItemViewModel playlist)
|
||||
{
|
||||
Text = playlist.Name;
|
||||
TreeItems = [];
|
||||
CanExpand = false;
|
||||
PlaylistId = playlist.Id;
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
|
||||
public string EndText { get; }
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using ErsatzTV.Application.Scheduling;
|
||||
using ErsatzTV.Application.Tree;
|
||||
using MudBlazor;
|
||||
|
||||
namespace ErsatzTV.ViewModels;
|
||||
@@ -14,6 +15,15 @@ public class TemplateTreeItemViewModel
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
|
||||
public TemplateTreeItemViewModel(TreeGroupViewModel templateGroup)
|
||||
{
|
||||
Text = templateGroup.Name;
|
||||
TreeItems = templateGroup.Children.Map(t => new TreeItemData<TemplateTreeItemViewModel>
|
||||
{ Value = new TemplateTreeItemViewModel(t) }).ToList();
|
||||
TemplateGroupId = templateGroup.Id;
|
||||
Icon = Icons.Material.Filled.Folder;
|
||||
}
|
||||
|
||||
public TemplateTreeItemViewModel(TemplateViewModel template)
|
||||
{
|
||||
Text = template.Name;
|
||||
@@ -22,6 +32,14 @@ public class TemplateTreeItemViewModel
|
||||
TemplateId = template.Id;
|
||||
}
|
||||
|
||||
public TemplateTreeItemViewModel(TreeItemViewModel template)
|
||||
{
|
||||
Text = template.Name;
|
||||
TreeItems = [];
|
||||
CanExpand = false;
|
||||
TemplateId = template.Id;
|
||||
}
|
||||
|
||||
public string Text { get; }
|
||||
|
||||
public string Icon { get; }
|
||||
|
||||
@@ -145,6 +145,10 @@
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.form-field-stack ul.mud-treeview .mud-typography {
|
||||
font-weight: unset;
|
||||
}
|
||||
|
||||
.form-field-stack .mud-typography,
|
||||
.mud-form .mud-typography-h5 {
|
||||
color: rgba(255, 255, 255, 0.90);
|
||||
@@ -155,7 +159,8 @@
|
||||
justify-content: flex-start;
|
||||
}
|
||||
|
||||
.form-field-stack div.mud-input-control {
|
||||
.form-field-stack div.mud-input-control,
|
||||
.form-field-stack ul.mud-treeview {
|
||||
max-width: 500px;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user