TASK 5 items 1-3: reusable stream, health banner, docs refresh
- Reusable stream: GetOrCreateReusableStreamAsync, cached via LayoutStore, bound at broadcast insert - Health monitoring: GetStreamHealthAsync polls liveStreams.status, report-by-exception banner - Go-live order: ensure stream → create broadcast → then start pump (URL must exist first) - Full broadcast form scoped (TASK 5 items 6-7) in TASKS.md + ai.md - TASK 23 trimmed to technical scope, TASK 26 added (marcom/launch kit) - Confidential files: MONETIZATION.md + MARCOM.md (gitignored, not committed) - .gitignore updated for confidential business files - HANDOFF.md updated with session state and next steps
This commit is contained in:
@@ -0,0 +1,26 @@
|
||||
using ytLive.Models;
|
||||
|
||||
namespace ytLive.Services;
|
||||
|
||||
/// <summary>Report-by-exception (TASK 5 item 3): turns liveStreams
|
||||
/// configuration issues into a banner. good/ok/noData and info-only issues
|
||||
/// produce no banner; the first warning/error issue produces its text, colored
|
||||
/// by the worst severity (error beats warning). Pure — fully testable.</summary>
|
||||
public static class StreamHealthReporter
|
||||
{
|
||||
public static HealthIssueReport BannerFor(IEnumerable<StreamConfigurationIssue> issues)
|
||||
{
|
||||
var reportable = issues
|
||||
.Where(i => i.Severity is StreamIssueSeverity.Warning or StreamIssueSeverity.Error)
|
||||
.ToList();
|
||||
if (reportable.Count == 0) return new HealthIssueReport(null, false);
|
||||
|
||||
var isError = reportable.Any(i => i.Severity == StreamIssueSeverity.Error);
|
||||
return new HealthIssueReport(
|
||||
string.Join(", ", reportable.Select(i => i.Type).Where(t => !string.IsNullOrWhiteSpace(t))),
|
||||
isError);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>null Text = no banner. IsError colors it: error → app red, else amber.</summary>
|
||||
public record HealthIssueReport(string? Text, bool IsError);
|
||||
Reference in New Issue
Block a user