/// <summary> /// Writes a notification for the specified <see cref="AggregatedAlert"/>. /// </summary> /// <param name="aggregatedAlert">An <see cref="AggregatedAlert"/> that should be written to the notification.</param> public void WriteAggregatedAlert(AggregatedAlert aggregatedAlert) { if (_tabLevel <= 1) { throw new InvalidOperationException("A status range must be entered before aggregated alerts can be written!"); } StatusAuditAlert auditAlert = aggregatedAlert.CommonAlert ?? StatusAuditAlert.None; StatusRatingRange range = StatusRating.FindRange(auditAlert.Rating); string rangeName = StatusRating.GetRangeName(range); string rangeColor = StatusRating.GetRangeForegroundColor(auditAlert.Rating); string rgbColor = StatusRating.GetRatingRgbForegroundColor(aggregatedAlert.RatingSum / aggregatedAlert.Sources.Count); List <StatusPropertyRange> propertyRanges = aggregatedAlert.PropertyRanges; OpenHeader(_details, _terse, _tabLevel, (StatusRatingRange)(-1), rgbColor); _terse.Append(aggregatedAlert.Target + ": " + aggregatedAlert.TerseSources + "->"); #if RAWRATINGS _details.Append("[RATING=" + auditAlert.Rating.ToString(DebugRatingFloatFormat) + "] "); #endif _details.Append(aggregatedAlert.Target + ": " + aggregatedAlert.DetailsSources + " reporting: "); // multi-line alert details or properties to list? if ((aggregatedAlert.CommonAlert?.Details != null && (aggregatedAlert.CommonAlert.Details.Contains("<br/>", StringComparison.Ordinal) || aggregatedAlert.CommonAlert.Details.Contains("</div>", StringComparison.Ordinal))) || (propertyRanges != null && propertyRanges.Count > 0)) { CloseHeader(_details, _terse, _tabLevel); EnterTabLevel(); OpenHeader(_details, _terse, _tabLevel, (StatusRatingRange)(-1), rgbColor); _terse.Append(RenderTerse(auditAlert.Terse).Replace("\n", "\n" + new string(' ', _tabLevel), StringComparison.Ordinal)); _details.AppendLine(RenderDetails(auditAlert.Details)); CloseHeader(_details, _terse, _tabLevel); // are there properties? if (propertyRanges != null && propertyRanges.Count > 0) { _details.Append(" because"); foreach (StatusPropertyRange propertyRange in aggregatedAlert.PropertyRanges) { OpenHeader(_details, _terse, _tabLevel, (StatusRatingRange)(-1), rgbColor); _terse.Append(propertyRange.ToString()); _details.AppendLine(propertyRange.ToString()); CloseHeader(_details, _terse, _tabLevel); } } LeaveTabLevel(); } else { _terse.Append(RenderTerse(auditAlert.Terse)); _details.Append(' '); _details.Append(RenderDetails(auditAlert.Details)); CloseHeader(_details, _terse, _tabLevel); } }
/// <summary> /// Enters a status range section for the range indicated by the rating. /// Should be matched by a subsequent call to <see cref="LeaveStatusRange"/>. /// </summary> /// <param name="rating">The status rating.</param> public void EnterStatusRange(float rating) { StatusRatingRange range = StatusRating.FindRange(rating); string rangeName = StatusRating.GetRangeName(range); string rangeColor = StatusRating.GetRangeForegroundColor(range); if (_tabLevel > 1) { throw new InvalidOperationException("All targets and status ranges must be closed before entering a new status range!"); } _details.Append("<div class=\""); #pragma warning disable CA1308 // this is to convert the range name from the C# style casing (Pascal) to the HTML style casing (kebab) _details.Append(rangeName.ToLowerInvariant()); #pragma warning restore CA1308 _details.Append("-range\">"); OpenHeader(_details, _terse, _tabLevel, range, rangeColor); _currentSectionRatingRange = range; _terse.Append(rangeName.ToUpperInvariant()); _details.Append(StatusRating.GetRangeSymbol(range)); _details.Append(' '); _details.Append(rangeName); if (_notificationTime != null) { _terse.Append(" @"); _terse.Append(_notificationTime.Value.ToShortTimeString()); _details.Append(" at "); _details.Append(_notificationTime.Value.ToLongTimeString()); _notificationTime = null; } CloseHeader(_details, _terse, _tabLevel); EnterTabLevel(); }