Skip to content
Snippets Groups Projects
Commit 1ac07b8c authored by Dmytro Bogatov's avatar Dmytro Bogatov :two_hearts:
Browse files

Endpoint for resolve.

parent 331ec3c6
Branches
No related tags found
No related merge requests found
Pipeline #
...@@ -6,17 +6,47 @@ import "bootstrap-select" ...@@ -6,17 +6,47 @@ import "bootstrap-select"
import * as Waves from "Waves" import * as Waves from "Waves"
import "bootstrap" import "bootstrap"
declare global {
interface JQuery {
jsonViewer(any): void;
}
}
$(async () => { $(async () => {
$('.selectpicker').selectpicker(); $('.selectpicker').selectpicker();
Utility.fixUtcTime(); Utility.fixUtcTime();
setupDiscrepancyViewer();
document.dispatchEvent(new Event("page-ready")); 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 ...@@ -34,6 +34,8 @@ namespace StatusMonitor.Web.Controllers.View
private readonly IServiceProvider _provider; private readonly IServiceProvider _provider;
private readonly ICleanService _cleanService; private readonly ICleanService _cleanService;
private readonly IDataContext _context; private readonly IDataContext _context;
private readonly INotificationService _notification;
private readonly IConfiguration _config;
public AdminController( public AdminController(
...@@ -42,7 +44,9 @@ namespace StatusMonitor.Web.Controllers.View ...@@ -42,7 +44,9 @@ namespace StatusMonitor.Web.Controllers.View
IMetricService metricService, IMetricService metricService,
IServiceProvider provider, IServiceProvider provider,
ICleanService cleanService, ICleanService cleanService,
IDataContext context IDataContext context,
INotificationService notification,
IConfiguration congig
) )
{ {
_metricService = metricService; _metricService = metricService;
...@@ -51,6 +55,8 @@ namespace StatusMonitor.Web.Controllers.View ...@@ -51,6 +55,8 @@ namespace StatusMonitor.Web.Controllers.View
_provider = provider; _provider = provider;
_cleanService = cleanService; _cleanService = cleanService;
_context = context; _context = context;
_notification = notification;
_config = congig;
} }
public async Task<IActionResult> Index() public async Task<IActionResult> Index()
...@@ -84,6 +90,65 @@ namespace StatusMonitor.Web.Controllers.View ...@@ -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) public IActionResult Metric([FromQuery] string metric)
{ {
if (metric == null) 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 @@ ...@@ -149,7 +149,11 @@
{ {
@foreach (var dicrepancy in ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Where(d => !d.Resolved)) @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 else
...@@ -160,10 +164,40 @@ ...@@ -160,10 +164,40 @@
<div role="tabpanel" class="tab-pane" id="resovled"> <div role="tabpanel" class="tab-pane" id="resovled">
@if ( ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Any(d => d.Resolved) ) @if ( ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Any(d => d.Resolved) )
{ {
var number = 1;
@foreach (var dicrepancy in ((IEnumerable<Discrepancy>)ViewBag.Discrepancies).Where(d => d.Resolved)) @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 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"> <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> </div>
@if (!Model.Resolved) @if (!Model.Resolved)
{ {
<div class="pull-right"> <div class="pull-right">
<div class="actions"> <div class="actions">
<!-- TODO form --> <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"> <button type="submit" class="btn btn-success btn-md waves-effect">
Resolve Resolve
</button> </button>
</form>
</div>
</div> </div>
}
else
{
<div class="pull-right">
<p>#@ViewBag.Number
</div> </div>
} }
...@@ -22,7 +43,7 @@ ...@@ -22,7 +43,7 @@
<small class="lgi-text">@Model.Description()</small> <small class="lgi-text">@Model.Description()</small>
<ul class="lgi-attrs"> <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) @if (Model.Resolved)
{ {
<li>Date resolved: <utc-time time="@Model.DateResolved" /></li> <li>Date resolved: <utc-time time="@Model.DateResolved" /></li>
... ...
......
...@@ -13,10 +13,13 @@ namespace StatusMonitor.Web.Views.ViewComponents ...@@ -13,10 +13,13 @@ namespace StatusMonitor.Web.Views.ViewComponents
[ViewComponent(Name = "DiscrepancyCard")] [ViewComponent(Name = "DiscrepancyCard")]
public class DiscrepancyCardViewComponent : ViewComponent 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; await Task.CompletedTask;
ViewBag.Number = number;
ViewBag.Hidden = hidden;
return View(model); return View(model);
} }
} }
... ...
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please to comment