|
60 | 60 | </ul> |
61 | 61 |
|
62 | 62 | <div class="tab-content pt-3"> |
| 63 | + @{ |
| 64 | + var mapsById = Model.Maps.ToDictionary(m => m.MapId); |
| 65 | + var mapsByName = Model.Maps.ToDictionary(m => m.MapName, StringComparer.OrdinalIgnoreCase); |
| 66 | + var serverMapNames = Model.ServerMaps.Select(m => m.Name).ToHashSet(StringComparer.OrdinalIgnoreCase); |
| 67 | + var serverMapsByName = Model.ServerMaps.ToDictionary(m => m.Name, StringComparer.OrdinalIgnoreCase); |
| 68 | + } |
63 | 69 |
|
64 | 70 | @* Tab 1: Current Rotation *@ |
65 | 71 | <div class="tab-pane fade show active" id="rotation-tab" role="tabpanel" aria-labelledby="rotation-tab-btn"> |
|
80 | 86 | · @(Model.ActiveRotation.MapRotationMaps?.Count ?? 0) maps · Version @Model.ActiveRotation.Version |
81 | 87 | </small> |
82 | 88 | </div> |
| 89 | + @{ |
| 90 | + var rotMapsForHealth = Model.ActiveRotation.MapRotationMaps ?? []; |
| 91 | + var missingFromHost = rotMapsForHealth.Count(rm => |
| 92 | + { |
| 93 | + var mapName = mapsById.TryGetValue(rm.MapId, out var m) ? m.MapName : null; |
| 94 | + return mapName != null && !serverMapNames.Contains(mapName); |
| 95 | + }); |
| 96 | + var problematicCount = rotMapsForHealth.Count(rm => mapsById.TryGetValue(rm.MapId, out var m) && m.MapStatus == MapHealthStatus.Problematic); |
| 97 | + var blacklistedCount = rotMapsForHealth.Count(rm => mapsById.TryGetValue(rm.MapId, out var m) && m.MapStatus == MapHealthStatus.Blacklisted); |
| 98 | + } |
| 99 | + @if (missingFromHost > 0 || problematicCount > 0 || blacklistedCount > 0) |
| 100 | + { |
| 101 | + <div class="alert alert-warning py-2 mb-3"> |
| 102 | + <i class="fa-solid fa-triangle-exclamation me-1"></i> |
| 103 | + <strong>Health warnings:</strong> |
| 104 | + @if (missingFromHost > 0) |
| 105 | + { |
| 106 | + <span class="ms-2"><span class="badge bg-danger"><i class="fa-solid fa-cloud-arrow-up"></i> @missingFromHost Not On Host</span></span> |
| 107 | + } |
| 108 | + @if (blacklistedCount > 0) |
| 109 | + { |
| 110 | + <span class="ms-2"><span class="badge bg-danger"><i class="fa-solid fa-ban"></i> @blacklistedCount Blacklisted</span></span> |
| 111 | + } |
| 112 | + @if (problematicCount > 0) |
| 113 | + { |
| 114 | + <span class="ms-2"><span class="badge bg-warning text-dark"><i class="fa-solid fa-triangle-exclamation"></i> @problematicCount Problematic</span></span> |
| 115 | + } |
| 116 | + </div> |
| 117 | + } |
83 | 118 | <div class="table-responsive"> |
84 | 119 | <table id="mapRotationTable" class="table table-striped table-hover w-100"> |
85 | 120 | <thead> |
|
96 | 131 | @for (var i = 0; i < sortedRotMaps.Count; i++) |
97 | 132 | { |
98 | 133 | var rotMap = sortedRotMaps[i]; |
99 | | - var map = Model.Maps.FirstOrDefault(m => m.MapId == rotMap.MapId); |
| 134 | + mapsById.TryGetValue(rotMap.MapId, out var map); |
100 | 135 | var mapName = map?.MapName ?? rotMap.MapId.ToString(); |
101 | | - var remoteMatch = Model.ServerMaps.FirstOrDefault(x => string.Equals(x.Name, mapName, StringComparison.OrdinalIgnoreCase)); |
| 136 | + var remoteMatch = serverMapsByName.ContainsKey(mapName); |
102 | 137 | <tr> |
103 | 138 | <td><small class="text-muted">@(i + 1)</small></td> |
104 | | - <td>@mapName</td> |
105 | 139 | <td> |
106 | | - @if (remoteMatch != null) |
| 140 | + @mapName |
| 141 | + @if (map?.MapStatus == MapHealthStatus.Blacklisted) |
| 142 | + { |
| 143 | + <span class="badge bg-danger ms-1" title="This map is blacklisted"><i class="fa-solid fa-ban"></i> Blacklisted</span> |
| 144 | + } |
| 145 | + else if (map?.MapStatus == MapHealthStatus.Problematic) |
| 146 | + { |
| 147 | + <span class="badge bg-warning text-dark ms-1" title="This map has known issues"><i class="fa-solid fa-triangle-exclamation"></i> Problematic</span> |
| 148 | + } |
| 149 | + </td> |
| 150 | + <td> |
| 151 | + @if (remoteMatch) |
107 | 152 | { |
108 | 153 | <span class="badge bg-success">On Host</span> |
109 | 154 | } |
110 | 155 | else |
111 | 156 | { |
112 | | - <span class="badge bg-danger">Not On Host</span> |
| 157 | + <span class="badge bg-danger"><i class="fa-solid fa-cloud-arrow-up"></i> Not On Host</span> |
113 | 158 | } |
114 | 159 | </td> |
115 | 160 | <td> |
|
149 | 194 | <tbody> |
150 | 195 | @foreach (var item in Model.RconMaps.OrderBy(x => x.MapName)) |
151 | 196 | { |
152 | | - var map = Model.Maps.FirstOrDefault(x => x.MapName == item.MapName); |
153 | | - var remoteMatch = Model.ServerMaps.FirstOrDefault(x => x.Name == item.MapName); |
| 197 | + mapsByName.TryGetValue(item.MapName, out var map); |
| 198 | + var remoteMatch = serverMapsByName.ContainsKey(item.MapName); |
154 | 199 | <tr> |
155 | | - <td>@item.MapName</td> |
156 | 200 | <td> |
157 | | - @if (remoteMatch != null) |
| 201 | + @item.MapName |
| 202 | + @if (map?.MapStatus == MapHealthStatus.Blacklisted) |
| 203 | + { |
| 204 | + <span class="badge bg-danger ms-1" title="This map is blacklisted"><i class="fa-solid fa-ban"></i> Blacklisted</span> |
| 205 | + } |
| 206 | + else if (map?.MapStatus == MapHealthStatus.Problematic) |
| 207 | + { |
| 208 | + <span class="badge bg-warning text-dark ms-1" title="This map has known issues"><i class="fa-solid fa-triangle-exclamation"></i> Problematic</span> |
| 209 | + } |
| 210 | + </td> |
| 211 | + <td> |
| 212 | + @if (remoteMatch) |
158 | 213 | { |
159 | 214 | <span class="badge bg-success">On Host</span> |
160 | 215 | } |
161 | 216 | else |
162 | 217 | { |
163 | | - <span class="badge bg-danger">Not On Host</span> |
| 218 | + <span class="badge bg-danger"><i class="fa-solid fa-cloud-arrow-up"></i> Not On Host</span> |
164 | 219 | } |
165 | 220 | </td> |
166 | 221 | <td> |
|
204 | 259 | <th>Name</th> |
205 | 260 | <th>Path</th> |
206 | 261 | <th style="width: 110px;">Rotation Status</th> |
| 262 | + <th style="width: 100px;">Health</th> |
207 | 263 | <th style="width: 120px;">Modified</th> |
208 | 264 | <th style="width: 60px;"></th> |
209 | 265 | </tr> |
210 | 266 | </thead> |
211 | 267 | <tbody> |
212 | 268 | @foreach (var item in Model.ServerMaps) |
213 | 269 | { |
| 270 | + mapsByName.TryGetValue(item.Name, out var portalMap); |
214 | 271 | <tr> |
215 | 272 | <td>@item.Name</td> |
216 | 273 | <td><small class="text-muted">@item.FullName</small></td> |
|
228 | 285 | } |
229 | 286 | } |
230 | 287 | </td> |
| 288 | + <td> |
| 289 | + @if (portalMap?.MapStatus == MapHealthStatus.Blacklisted) |
| 290 | + { |
| 291 | + <span class="badge bg-danger" title="This map is blacklisted"><i class="fa-solid fa-ban"></i> Blacklisted</span> |
| 292 | + } |
| 293 | + else if (portalMap?.MapStatus == MapHealthStatus.Problematic) |
| 294 | + { |
| 295 | + <span class="badge bg-warning text-dark" title="This map has known issues"><i class="fa-solid fa-triangle-exclamation"></i> Problematic</span> |
| 296 | + } |
| 297 | + else |
| 298 | + { |
| 299 | + <span class="badge bg-light text-muted">OK</span> |
| 300 | + } |
| 301 | + </td> |
231 | 302 | <td><small>@item.Modified.ToString("yyyy-MM-dd")</small></td> |
232 | 303 | <td> |
233 | 304 | <partial name="DeleteMapFromHostPartial" model="@(new DeleteMapFromHostModel(Model.GameServer.GameServerId, item.Name))"></partial> |
|
270 | 341 | <tr> |
271 | 342 | <th>Rotation</th> |
272 | 343 | <th style="width: 80px;">Mode</th> |
| 344 | + <th style="width: 80px;">Health</th> |
273 | 345 | <th style="width: 90px;">Deploy</th> |
274 | 346 | <th style="width: 90px;">Active</th> |
275 | 347 | <th style="width: 80px;"></th> |
|
294 | 366 | </small> |
295 | 367 | </td> |
296 | 368 | <td><span class="badge bg-info">@(rotation?.GameMode ?? "—")</span></td> |
| 369 | + <td> |
| 370 | + @{ |
| 371 | + var rotMaps = rotation?.MapRotationMaps ?? []; |
| 372 | + var healthIssues = rotMaps.Count(rm => mapsById.TryGetValue(rm.MapId, out var m) && m.MapStatus != MapHealthStatus.OK); |
| 373 | + var notOnHost = rotMaps.Count(rm => { |
| 374 | + var mapName = mapsById.TryGetValue(rm.MapId, out var m) ? m.MapName : null; |
| 375 | + return mapName != null && !serverMapNames.Contains(mapName); |
| 376 | + }); |
| 377 | + var totalWarnings = healthIssues + notOnHost; |
| 378 | + } |
| 379 | + @if (totalWarnings > 0) |
| 380 | + { |
| 381 | + <span class="badge bg-warning text-dark" title="@healthIssues health issue(s), @notOnHost not on host"> |
| 382 | + <i class="fa-solid fa-triangle-exclamation"></i> @totalWarnings |
| 383 | + </span> |
| 384 | + } |
| 385 | + else |
| 386 | + { |
| 387 | + <span class="badge bg-light text-muted">OK</span> |
| 388 | + } |
| 389 | + </td> |
297 | 390 | <td> |
298 | 391 | @switch (assignment.DeploymentState) |
299 | 392 | { |
|
0 commit comments