Add webhook delivery status indicator (#2679)

* Add webhook delivery status indicator

As discussed in: https://github.com/btcpayserver/btcpayserver/discussions/2616

* Add relative delivery time to tooltips
This commit is contained in:
Umar Bolatov
2021-07-12 05:58:11 -07:00
committed by GitHub
parent d5019f61ce
commit 861e5b1530
3 changed files with 50 additions and 14 deletions

View File

@@ -4,6 +4,7 @@ using System.Threading.Tasks;
using BTCPayServer.Data; using BTCPayServer.Data;
using BTCPayServer.Models; using BTCPayServer.Models;
using BTCPayServer.Models.StoreViewModels; using BTCPayServer.Models.StoreViewModels;
using BTCPayServer.Client.Models;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using NBitcoin; using NBitcoin;
using NBitcoin.DataEncoders; using NBitcoin.DataEncoders;
@@ -18,17 +19,31 @@ namespace BTCPayServer.Controllers
return View("Integrations", new IntegrationsViewModel()); return View("Integrations", new IntegrationsViewModel());
} }
private async Task<Data.WebhookDeliveryData?> LastDeliveryForWebhook(string webhookId)
{
return (await _Repo.GetWebhookDeliveries(CurrentStore.Id, webhookId, 1)).ToList().FirstOrDefault();
}
[HttpGet("{storeId}/webhooks")] [HttpGet("{storeId}/webhooks")]
public async Task<IActionResult> Webhooks() public async Task<IActionResult> Webhooks()
{ {
var webhooks = await _Repo.GetWebhooks(CurrentStore.Id); var webhooks = await _Repo.GetWebhooks(CurrentStore.Id);
return View(nameof(Webhooks), new WebhooksViewModel() return View(nameof(Webhooks), new WebhooksViewModel()
{
Webhooks = webhooks.Select(w => new WebhooksViewModel.WebhookViewModel()
{ {
Id = w.Id, Webhooks = webhooks.Select(async w => {
Url = w.GetBlob().Url var lastDelivery = await LastDeliveryForWebhook(w.Id);
}).ToArray() var lastDeliveryBlob = lastDelivery?.GetBlob();
return new WebhooksViewModel.WebhookViewModel()
{
Id = w.Id,
Url = w.GetBlob().Url,
LastDeliveryErrorMessage = lastDeliveryBlob?.ErrorMessage,
LastDeliveryTimeStamp = lastDelivery?.Timestamp,
LastDeliverySuccessful = lastDeliveryBlob == null ? true : lastDeliveryBlob.Status == WebhookDeliveryStatus.HttpSuccess,
};
}
).Select(t => t.Result).ToArray()
}); });
} }

View File

@@ -1,7 +1,5 @@
#nullable enable
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace BTCPayServer.Models.StoreViewModels namespace BTCPayServer.Models.StoreViewModels
{ {
@@ -11,6 +9,9 @@ namespace BTCPayServer.Models.StoreViewModels
{ {
public string Id { get; set; } public string Id { get; set; }
public string Url { get; set; } public string Url { get; set; }
public bool LastDeliverySuccessful { get; set; } = true;
public DateTimeOffset? LastDeliveryTimeStamp { get; set; } = null;
public string? LastDeliveryErrorMessage { get; set; } = null;
} }
public WebhookViewModel[] Webhooks { get; set; } public WebhookViewModel[] Webhooks { get; set; }
} }

View File

@@ -17,19 +17,39 @@
{ {
<table class="table table-sm table-responsive-md"> <table class="table table-sm table-responsive-md">
<thead> <thead>
<tr> <tr>
<th>Url</th> <th>Status</th>
<th class="text-end">Actions</th> <th>Url</th>
</tr> <th class="text-end">Actions</th>
</tr>
</thead> </thead>
<tbody> <tbody>
@foreach (var wh in Model.Webhooks) @foreach (var wh in Model.Webhooks)
{ {
<tr> <tr>
<td class="align-baseline">
@if (wh.LastDeliverySuccessful)
{
<span
class="fa fa-check text-success"
id="delivery-status-icon"
data-bs-toggle="tooltip"
title="@(wh.LastDeliveryTimeStamp == null ? "No deliveries for this webhook yet" : "Last delivery " + @wh.LastDeliveryTimeStamp?.ToTimeAgo())"></span>
}
else
{
<span
class="fa fa-times text-danger"
id="delivery-status-icon"
data-bs-toggle="tooltip"
data-bs-html="true"
title="Error: @wh.LastDeliveryErrorMessage. <br/> Delivery last attempted <span id='last-delivery-time'>@wh.LastDeliveryTimeStamp?.ToTimeAgo()</span>"></span>
}
</td>
<td class="d-block text-break">@wh.Url</td> <td class="d-block text-break">@wh.Url</td>
<td class="text-end text-md-nowrap"> <td class="text-end text-md-nowrap">
<a asp-action="TestWebhook" asp-route-storeId="@this.Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Test</a> - <a asp-action="TestWebhook" asp-route-storeId="@this.Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Test</a> -
<a asp-action="ModifyWebhook" asp-route-storeId="@this.Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Modify</a> - <a asp-action="ModifyWebhook" asp-route-storeId="@this.Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Modify</a> -
<a asp-action="DeleteWebhook" asp-route-storeId="@this.Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Delete</a> <a asp-action="DeleteWebhook" asp-route-storeId="@this.Context.GetRouteValue("storeId")" asp-route-webhookId="@wh.Id">Delete</a>
</td> </td>
</tr> </tr>
@@ -45,5 +65,5 @@ else
} }
@section PageFootContent { @section PageFootContent {
<partial name="_ValidationScriptsPartial" /> <partial name="_ValidationScriptsPartial" />
} }