|
16 | 16 | <small class="text-muted">Query ID: @Response.QueryId</small> |
17 | 17 | </div> |
18 | 18 | </div> |
| 19 | + |
| 20 | + @* Data Source Indicators - Top Level Design Element *@ |
| 21 | + @if (Response.Results?.Any() == true) |
| 22 | + { |
| 23 | + <div class="card-body border-bottom bg-light"> |
| 24 | + <h6 class="mb-3"><i class="fas fa-database me-2"></i>Data Sources</h6> |
| 25 | + <div class="row g-3"> |
| 26 | + @{ |
| 27 | + var rssCount = Response.Results.Count(r => r.Site == "devblogs.microsoft.com"); |
| 28 | + var mockCount = Response.Results.Count(r => r.Name.StartsWith("[Mock Data]")); |
| 29 | + var staticCount = Response.Results.Count - rssCount - mockCount; |
| 30 | + } |
| 31 | + |
| 32 | + @* RSS Feed Data Source *@ |
| 33 | + <div class="col-md-4"> |
| 34 | + <div class="card h-100 @(rssCount > 0 ? "border-primary" : "border-secondary opacity-50")"> |
| 35 | + <div class="card-body text-center"> |
| 36 | + <div class="mb-2"> |
| 37 | + <i class="fas fa-rss fa-2x @(rssCount > 0 ? "text-primary" : "text-secondary")"></i> |
| 38 | + </div> |
| 39 | + <h6 class="card-title">Live RSS Feeds</h6> |
| 40 | + <p class="card-text small text-muted">.NET Blog & News</p> |
| 41 | + <span class="badge @(rssCount > 0 ? "bg-primary" : "bg-secondary")"> |
| 42 | + @rssCount result(s) |
| 43 | + </span> |
| 44 | + </div> |
| 45 | + </div> |
| 46 | + </div> |
| 47 | + |
| 48 | + @* Static Schema.org Data Source *@ |
| 49 | + <div class="col-md-4"> |
| 50 | + <div class="card h-100 @(staticCount > 0 ? "border-info" : "border-secondary opacity-50")"> |
| 51 | + <div class="card-body text-center"> |
| 52 | + <div class="mb-2"> |
| 53 | + <i class="fas fa-rocket fa-2x @(staticCount > 0 ? "text-info" : "text-secondary")"></i> |
| 54 | + </div> |
| 55 | + <h6 class="card-title">Schema.org Static Data</h6> |
| 56 | + <p class="card-text small text-muted">Science Fiction Content</p> |
| 57 | + <span class="badge @(staticCount > 0 ? "bg-info" : "bg-secondary")"> |
| 58 | + @staticCount result(s) |
| 59 | + </span> |
| 60 | + </div> |
| 61 | + </div> |
| 62 | + </div> |
| 63 | + |
| 64 | + @* Mock Data Source *@ |
| 65 | + <div class="col-md-4"> |
| 66 | + <div class="card h-100 @(mockCount > 0 ? "border-warning" : "border-secondary opacity-50")"> |
| 67 | + <div class="card-body text-center"> |
| 68 | + <div class="mb-2"> |
| 69 | + <i class="fas fa-flask fa-2x @(mockCount > 0 ? "text-warning" : "text-secondary")"></i> |
| 70 | + </div> |
| 71 | + <h6 class="card-title">Mock Data</h6> |
| 72 | + <p class="card-text small text-muted">Placeholder Content</p> |
| 73 | + <span class="badge @(mockCount > 0 ? "bg-warning" : "bg-secondary")"> |
| 74 | + @mockCount result(s) |
| 75 | + </span> |
| 76 | + </div> |
| 77 | + </div> |
| 78 | + </div> |
| 79 | + </div> |
| 80 | + </div> |
| 81 | + } |
| 82 | + |
19 | 83 | <div class="card-body"> |
20 | 84 | @if (!string.IsNullOrEmpty(Response.Summary)) |
21 | 85 | { |
|
77 | 141 | } |
78 | 142 | </h6> |
79 | 143 | <span class="badge bg-primary">@result.Score.ToString("F2")</span> |
80 | | - </div> |
81 | | - @if (!string.IsNullOrEmpty(result.Description)) |
| 144 | + </div> @if (!string.IsNullOrEmpty(result.Description)) |
82 | 145 | { |
83 | | - <p class="card-text small">@result.Description</p> |
84 | | - } |
85 | | - @if (!string.IsNullOrEmpty(result.Site)) |
| 146 | + <p class="card-text small">@((MarkupString)FormatDescription(result))</p> |
| 147 | + } @if (!string.IsNullOrEmpty(result.Site)) |
86 | 148 | { |
87 | 149 | <div class="mt-2"> |
| 150 | + @{ |
| 151 | + var badgeClass = GetDataSourceBadgeClass(result); |
| 152 | + var sourceLabel = GetDataSourceLabel(result); |
| 153 | + } |
| 154 | + <span class="badge @badgeClass me-1">@sourceLabel</span> |
88 | 155 | <span class="badge bg-secondary">@result.Site</span> |
89 | 156 | </div> |
90 | 157 | } |
|
115 | 182 | { |
116 | 183 | @result.Name |
117 | 184 | } |
118 | | - </h6> |
119 | | - <div> |
| 185 | + </h6> <div> |
120 | 186 | <span class="badge bg-primary me-2">@result.Score.ToString("F2")</span> |
| 187 | + @{ |
| 188 | + var badgeClass = GetDataSourceBadgeClass(result); |
| 189 | + var sourceLabel = GetDataSourceLabel(result); |
| 190 | + } |
| 191 | + <span class="badge @badgeClass me-1">@sourceLabel</span> |
121 | 192 | @if (!string.IsNullOrEmpty(result.Site)) |
122 | 193 | { |
123 | 194 | <span class="badge bg-secondary">@result.Site</span> |
124 | 195 | } |
125 | 196 | </div> |
126 | | - </div> |
127 | | - @if (!string.IsNullOrEmpty(result.Description)) |
| 197 | + </div> @if (!string.IsNullOrEmpty(result.Description)) |
128 | 198 | { |
129 | | - <p class="mb-1 small">@result.Description</p> |
| 199 | + <p class="mb-1 small">@((MarkupString)FormatDescription(result))</p> |
130 | 200 | } |
131 | 201 | </div> |
132 | 202 | } |
|
236 | 306 | .Replace("**", "</strong>"); |
237 | 307 |
|
238 | 308 | return formatted; |
239 | | - } |
240 | | - |
241 | | - private string FormatJson(object? obj) |
| 309 | + } private string FormatJson(object? obj) |
242 | 310 | { |
243 | 311 | if (obj == null) return "null"; |
244 | 312 |
|
|
253 | 321 | { |
254 | 322 | return obj.ToString() ?? "null"; |
255 | 323 | } |
| 324 | + } private string FormatDescription(NLWebResult result) |
| 325 | + { |
| 326 | + if (string.IsNullOrEmpty(result.Description)) |
| 327 | + return ""; |
| 328 | + |
| 329 | + var description = result.Description; |
| 330 | + |
| 331 | + // Remove HTML tags ONLY for RSS content from devblogs.microsoft.com |
| 332 | + if (result.Site == "devblogs.microsoft.com") |
| 333 | + { |
| 334 | + description = StripHtmlTags(description); |
| 335 | + } |
| 336 | + |
| 337 | + return description; |
| 338 | + }private bool IsRssContent(NLWebResult result) |
| 339 | + { |
| 340 | + // RSS content is ONLY from devblogs.microsoft.com |
| 341 | + // Static sci-fi content should NOT be considered RSS even if it has BlogPosting type |
| 342 | + return result.Site == "devblogs.microsoft.com"; |
| 343 | + } |
| 344 | + |
| 345 | + private string StripHtmlTags(string html) |
| 346 | + { |
| 347 | + if (string.IsNullOrEmpty(html)) |
| 348 | + return ""; |
| 349 | + |
| 350 | + // Basic HTML tag removal - removes anything between < and > |
| 351 | + return System.Text.RegularExpressions.Regex.Replace(html, "<.*?>", string.Empty); |
| 352 | + } |
| 353 | + |
| 354 | + private string GetDataSourceBadgeClass(NLWebResult result) |
| 355 | + { |
| 356 | + if (result.Name.StartsWith("[Mock Data]")) |
| 357 | + return "bg-warning"; |
| 358 | + |
| 359 | + if (result.Site == "devblogs.microsoft.com" || IsRssContent(result)) |
| 360 | + return "bg-primary"; |
| 361 | + |
| 362 | + return "bg-info"; // Static Schema.org content |
| 363 | + } |
| 364 | + |
| 365 | + private string GetDataSourceLabel(NLWebResult result) |
| 366 | + { |
| 367 | + if (result.Name.StartsWith("[Mock Data]")) |
| 368 | + return "Mock"; |
| 369 | + |
| 370 | + if (result.Site == "devblogs.microsoft.com" || IsRssContent(result)) |
| 371 | + return "RSS"; |
| 372 | + |
| 373 | + return "Schema.org"; // Static content |
256 | 374 | } |
257 | 375 | } |
0 commit comments