Commit 1ac07b8c authored by Dmytro Bogatov's avatar Dmytro Bogatov 💕

Endpoint for resolve.

parent 331ec3c6
Pipeline #588 failed with stages
in 4 minutes and 17 seconds
......@@ -6,17 +6,47 @@ import "bootstrap-select"
import * as Waves from "Waves"
import "bootstrap"
declare global {
interface JQuery {
jsonViewer(any): void;
}
}
$(async () => {
$('.selectpicker').selectpicker();
Utility.fixUtcTime();
setupDiscrepancyViewer();
document.dispatchEvent(new Event("page-ready"));
});
function setupDiscrepancyViewer() {
var resolvedLoaded = 10;
$("#load-more-resolved-btn").click(() => {
for (var index = resolvedLoaded + 1; index <= resolvedLoaded + 10; index++) {
$(`.discrepancy-card[data-number="${index}"]`).show();
}
resolvedLoaded += 10;
$("#load-less-resolved-btn").show();
if (resolvedLoaded >= $(".discrepancy-resolved").length) {
$("#load-more-resolved-btn").hide();
}
});
$("#load-less-resolved-btn").click(() => {
for (var index = resolvedLoaded; index > resolvedLoaded - 10; index--) {
$(`.discrepancy-card[data-number="${index}"]`).hide();
}
resolvedLoaded -= 10;
$("#load-more-resolved-btn").show();
if (resolvedLoaded <= 10) {
$("#load-less-resolved-btn").hide();
}
});
}
......@@ -34,6 +34,8 @@ namespace StatusMonitor.Web.Controllers.View
private readonly IServiceProvider _provider;
private readonly ICleanService _cleanService;
private readonly IDataContext _context;
private readonly INotificationService _notification;
private readonly IConfiguration _config;
public AdminController(
......@@ -42,7 +44,9 @@ namespace StatusMonitor.Web.Controllers.View
IMetricService metricService,
IServiceProvider provider,
ICleanService cleanService,
IDataContext context
IDataContext context,
INotificationService notification,
IConfiguration congig
)
{
_metricService = metricService;
......@@ -51,6 +55,8 @@ namespace StatusMonitor.Web.Controllers.View
_provider = provider;
_cleanService = cleanService;
_context = context;
_notification = notification;
_config = congig;
}
public async Task<IActionResult> Index()
......@@ -84,6 +90,65 @@ namespace StatusMonitor.Web.Controllers.View
}
}
[HttpPost]
[ServiceFilter(typeof(ModelValidation))]
[AutoValidateAntiforgeryToken]
public async Task<IActionResult> ResolveDiscrepancy(DiscrepancyResolutionViewModel model)
{
if (
await _context
.Discrepancies
.AnyAsync(
d =>
d.DateFirstOffense == model.DateFirstOffense &&
d.MetricSource == model.Source &&
d.MetricType == model.EnumMetricType &&
d.Type == model.EnumDiscrepancyType
)
)
{
var discrepancy =
await _context
.Discrepancies
.SingleAsync(
d =>
d.DateFirstOffense == model.DateFirstOffense &&
d.MetricSource == model.Source &&
d.MetricType == model.EnumMetricType &&
d.Type == model.EnumDiscrepancyType
);
if (discrepancy.Resolved)
{
TempData["MessageSeverity"] = "warning";
TempData["MessageContent"] = $"Discrepancy {model.EnumDiscrepancyType} from {model.EnumMetricType} of {model.Source} at {model.DateFirstOffense} (UTC) has been already resolved.";
}
else
{
discrepancy.Resolved = true;
discrepancy.DateResolved = DateTime.UtcNow;
await _notification.ScheduleNotificationAsync(
$"Discrepancy \"{discrepancy.ToStringWithTimeZone(_config["ServiceManager:NotificationService:TimeZone"])}\" has been resolved!",
NotificationSeverity.Medium
);
await _context.SaveChangesAsync();
TempData["MessageSeverity"] = "success";
TempData["MessageContent"] = $"Discrepancy {model.EnumDiscrepancyType} from {model.EnumMetricType} of {model.Source} at {model.DateFirstOffense} (UTC) has been resolved.";
}
return RedirectToAction("Index", "Admin");
}
else
{
return NotFound($"Discrepancy for the following request not found. {model}");
}
}
public IActionResult Metric([FromQuery] string metric)
{
if (metric == null)
......
using System;
using System.ComponentModel.DataAnnotations;
using StatusMonitor.Shared.Extensions;
using StatusMonitor.Shared.Models.Entities;
namespace StatusMonitor.Web.ViewModels
{
public class DiscrepancyResolutionViewModel
{
public DateTime DateFirstOffense { get; set; }
/// <summary>
/// Alias for DateFirstOffense.
/// </summary>
[Required]
public string Date
{
get
{
return DateFirstOffense.ToString();
}
set
{
try
{
DateFirstOffense = new DateTime(Convert.ToInt64(value));
}
catch (System.Exception)
{
throw new ArgumentException("Invalid Date parameter.");
}
}
}
public DiscrepancyType EnumDiscrepancyType { get; set; }
/// <summary>
/// Alias for EnumDiscrepancyType.
/// </summary>
[Required]
public string DiscrepancyType
{
get
{
return EnumDiscrepancyType.ToString();
}
set
{
try
{
EnumDiscrepancyType = value.ToEnum<DiscrepancyType>();
}
catch (System.Exception)
{
throw new ArgumentException("Invalid DiscrepancyType parameter.");
}
}
}
public Metrics EnumMetricType { get; set; }
/// <summary>
/// Alias for EnumMetricType.
/// </summary>
[Required]
public string MetricType
{
get
{
return EnumMetricType.ToString();
}
set
{
try
{
EnumMetricType = value.ToEnum<Metrics>();
}
catch (System.Exception)
{
throw new ArgumentException("Invalid MetricType parameter.");
}
}
}
/// <summary>
/// Source identifier. May be server id or website URL.
/// </summary>
[Required]
[StringLength(32)]
[RegularExpression("[a-z0-9\\.\\-]+")]
public string Source { get; set; }
public override string ToString()
{
return $"Discrepancy removal model: type {DiscrepancyType} from {MetricType} of {Source} at {DateFirstOffense}.";
}
}
}
......@@ -149,7 +149,11 @@
{
@foreach (var dicrepancy in ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Where(d => !d.Resolved))
{
<vc:discrepancy-card model=dicrepancy></vc:discrepancy-card>
<vc:discrepancy-card
model=dicrepancy
number=0
hidden=false
></vc:discrepancy-card>
}
}
else
......@@ -160,10 +164,40 @@
<div role="tabpanel" class="tab-pane" id="resovled">
@if ( ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Any(d => d.Resolved) )
{
var number = 1;
@foreach (var dicrepancy in ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Where(d => d.Resolved))
{
<vc:discrepancy-card model=dicrepancy></vc:discrepancy-card>
var hidden = number > 10;
<vc:discrepancy-card
model=dicrepancy
number=number
hidden=hidden
></vc:discrepancy-card>
number++;
}
<div class="w-100 text-center p-t-10">
<button
type="type"
id="load-more-resolved-btn"
class="btn btn-primary btn-md waves-effect"
style="@( ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Count(d => d.Resolved) <= 10 ? "display: none;" : "")"
>
Show another 10
</button>
<button
type="type"
id="load-less-resolved-btn"
class="btn btn-warning btn-md waves-effect"
style="display: none;"
>
Hide another 10
</button>
</div>
}
else
{
......
<div class="list-group-item media">
<div
class="list-group-item media discrepancy-card discrepancy-@(Model.Resolved ? "resolved" : "unresolved")"
data-number="@ViewBag.Number"
style="@(ViewBag.Hidden ? "display: none;" : "")"
>
<div class="pull-left">
<i class="zmdi zmdi-@(Model.Resolved ? "check-circle" : "alert-circle-o") zmdi-hc-3x"></i>
<i
class="zmdi zmdi-@(Model.Resolved ? "check-circle" : "alert-circle-o") zmdi-hc-3x"
style="color: @(Model.Resolved ? "green" : "red");"
>
</i>
</div>
@if (!Model.Resolved)
{
<div class="pull-right">
<div class="actions">
<!-- TODO form -->
<button type="submit" class="btn btn-success btn-md waves-effect">
Resolve
</button>
<form asp-controller="Admin" asp-action="ResolveDiscrepancy" asp-anti-forgery="true">
<input type="text" hidden name="Date" value="@Model.DateFirstOffense.Ticks">
<input type="text" hidden name="DiscrepancyType" value="@Model.Type">
<input type="text" hidden name="MetricType" value="@Model.MetricType">
<input type="text" hidden name="Source" value="@Model.MetricSource">
<button type="submit" class="btn btn-success btn-md waves-effect">
Resolve
</button>
</form>
</div>
</div>
}
else
{
<div class="pull-right">
<p>#@ViewBag.Number
</div>
}
<div class="media-body">
<div class="lgi-heading">
......@@ -22,7 +43,7 @@
<small class="lgi-text">@Model.Description()</small>
<ul class="lgi-attrs">
<li>Date first offense: <utc-time time="@Model.DateFirstOffense" /></li>
<li>Date started: <utc-time time="@Model.DateFirstOffense" /></li>
@if (Model.Resolved)
{
<li>Date resolved: <utc-time time="@Model.DateResolved" /></li>
......
......@@ -13,10 +13,13 @@ namespace StatusMonitor.Web.Views.ViewComponents
[ViewComponent(Name = "DiscrepancyCard")]
public class DiscrepancyCardViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync(Discrepancy model)
public async Task<IViewComponentResult> InvokeAsync(Discrepancy model, int number = 0, bool hidden = false)
{
await Task.CompletedTask;
ViewBag.Number = number;
ViewBag.Hidden = hidden;
return View(model);
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment