< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Studio2_Views_JobLogs__WebhookLogTab
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/JobLogs/_WebhookLogTab.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 34
Coverable lines: 34
Total lines: 137
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 40
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
ExecuteAsync()0%1806420%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Studio2/Views/JobLogs/_WebhookLogTab.cshtml

#LineLine coverage
 1@using OzonDomains.Models.OzonWebhook
 2@model OzonOrdersWeb.Areas.Studio2.ViewModels.OzonWebhookViewModels.OzonWebhookIndexViewModel
 3@* Webhook Ozon — серверный грид (grid/webhook); «Открыть» — модалка с полным payload. *@
 4
 5@using Services.OzonWebhookServices.Monitoring
 6@{
 07    var health = Model.Availability;
 08    var isAdminUser = User.IsInRole("Admin") || User.IsInRole("SuperAdmin");
 09    var healthRows = new List<object>();
 010    foreach (var cabinet in health.Cabinets)
 11    {
 012        if (cabinet.Error != null)
 13        {
 014            healthRows.Add(new { cabinet = cabinet.ClientName, address = "—", status = "Ошибка проверки", reason = "Не у
 015            continue;
 16        }
 017        if (cabinet.Endpoints.Count == 0)
 18        {
 019            healthRows.Add(new { cabinet = cabinet.ClientName, address = "—", status = "Нет адресов", reason = "Адреса w
 020            continue;
 21        }
 022        foreach (var endpoint in cabinet.Endpoints)
 23        {
 024            var status = endpoint.IsChecking ? "На проверке" : !endpoint.Enabled ? "Отключён" : endpoint.Availability sw
 025            {
 026                OzonWebhookAvailability.Available => "Доступен",
 027                OzonWebhookAvailability.Unstable => "Нестабилен",
 028                OzonWebhookAvailability.Unavailable => "Недоступен",
 029                _ => "На проверке"
 030            };
 031            var tone = endpoint.IsProblem ? "danger" : endpoint.IsChecking || endpoint.Availability == OzonWebhookAvaila
 032            var reason = string.Join(" ", new[] { endpoint.Enabled ? null : OzonWebhookAvailabilitySnapshot.ReasonText(e
 033            healthRows.Add(new
 034            {
 035                cabinet = cabinet.ClientName,
 036                address = endpoint.DisplayUrl + (endpoint.Monitored ? string.Empty : " (чужой адрес, не контролируется)"
 037                status = endpoint.StatusDateUtc.HasValue ? status + " · " + endpoint.StatusDateUtc.Value.ToLocalTime().T
 038                reason, tone, canEnable = isAdminUser && endpoint.Monitored && !endpoint.Enabled,
 039                clientId = cabinet.ClientId, urlId = endpoint.Id
 040            });
 41        }
 42    }
 43}
 44
 45<section class="oz-wh-health @(health.HasProblem ? "oz-wh-health--bad" : "")" id="ozWebhookHealth">
 46    <div class="oz-wh-health__head">
 47        <strong><i class="fas fa-heart-pulse"></i> Доступность пуш-адресов (мониторинг Ozon)</strong>
 48        <span class="oz-wh-health__meta">
 049            @(health.CheckedAtUtc.HasValue ? "Проверено " + health.CheckedAtUtc.Value.ToLocalTime().ToString("dd.MM.yyyy
 50        </span>
 051        @if (isAdminUser)
 52        {
 53            <button type="button" class="btn btn-sm btn-outline-secondary" id="ozWebhookHealthRefresh">Проверить сейчас<
 54        }
 55    </div>
 56    <div class="oz-wh-health__hint">
 57        Ozon замеряет ответ раз в ночь: до 1500 мс — доступен, 1500–2500 мс — нестабилен, свыше 2500 мс — недоступен.
 58        Три дня «недоступен» подряд — Ozon отключает отправку, и статусы заказов перестают приходить пушами.
 59    </div>
 60    <div id="ozWebhookHealthGrid" class="bsx-grid oz-wh-health__grid"></div>
 61</section>
 62
 63<script>
 64    (function () {
 065        var rows = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(healthRows));
 66        var gridHost = document.getElementById('ozWebhookHealthGrid');
 67        var BG = window.BsxGrid;
 68        var esc = BG ? BG.esc : function (value) { return String(value ?? ''); };
 69        if (BG && gridHost) {
 70            var healthGrid = BG.localTable(gridHost, {
 71                key: 'jobLogsWebhookHealth',
 72                emptyText: 'Данных о пуш-адресах пока нет.',
 73                getRowId: function (p) { return `${p.data.cabinet}-${p.data.urlId || p.data.address}`; },
 74                gridOptions: { domLayout: 'autoHeight', rowHeight: 40 },
 75                columnDefs: [
 76                    { field: 'cabinet', headerName: 'Кабинет', width: 190, filter: 'agTextColumnFilter' },
 77                    { field: 'address', headerName: 'Адрес', flex: 1, minWidth: 330, filter: 'agTextColumnFilter', toolt
 78                    { field: 'status', headerName: 'Статус', width: 190, filter: 'agTextColumnFilter',
 79                        cellRenderer: function (p) { return p.data ? `<span class="bsx-tone bsx-tone--${esc(p.data.tone 
 80                    { field: 'reason', headerName: 'Причина', flex: 1, minWidth: 220, filter: 'agTextColumnFilter', tool
 81                    { colId: 'actions', headerName: '', width: 115, sortable: false, filter: false, lockVisible: true, c
 82                        cellRenderer: function (p) { return p.data && p.data.canEnable ? `<button type="button" class="b
 83                ]
 84            });
 85            healthGrid.setRows(rows);
 86        }
 87
 88        function post(url) { return fetch(url, { method: 'POST', headers: { Accept: 'application/json' } }).then(functio
 89        var refresh = document.getElementById('ozWebhookHealthRefresh');
 90        if (refresh) refresh.addEventListener('click', function () {
 91            refresh.disabled = true;
 92            post('/Studio2/JobLogs/webhook-health/refresh').then(function () { location.reload(); }).catch(function () {
 93        });
 94        gridHost?.addEventListener('click', async function (event) {
 95            var btn = event.target.closest('.oz-wh-enable');
 96            if (!btn) return;
 97                if (!(await St2Dialog.confirm('Включить отправку пуш-уведомлений на этот адрес? Убедитесь, что адрес отв
 98                btn.disabled = true;
 99                post('/Studio2/JobLogs/webhook-health/enable?clientId=' + btn.dataset.clientId + '&urlId=' + btn.dataset
 100                    .then(function (d) { if (d && d.success) location.reload(); else { alert((d && d.message) || 'Не уда
 101                    .catch(function () { btn.disabled = false; });
 102        });
 103    })();
 104</script>
 105
 106<div class="job-logs-intro">
 107    <i class="fas fa-circle-info"></i>
 108    <span>
 109        <strong>Received</strong> — принято, ещё не обработано; <strong>Processed</strong> — применено к заказу;
 110        <strong>Skipped</strong> — тип сообщения не обрабатывается; <strong>Error</strong> — обработчик упал,
 111        причина в колонке «Ошибка / результат».
 112    </span>
 113</div>
 114
 115<div class="job-logs-workflow">
 116    <div class="job-logs-workflow-step"><span class="job-logs-workflow-num">1</span><div><strong>Ozon отправляет webhook
 117    <div class="job-logs-workflow-step"><span class="job-logs-workflow-num">2</span><div><strong>Сообщение в очереди</st
 118    <div class="job-logs-workflow-step"><span class="job-logs-workflow-num">3</span><div><strong>Обработчик обновляет за
 119</div>
 120
 0121@await Html.PartialAsync("_JobLogsGridPanel", new OzonOrdersWeb.Areas.Studio2.ViewModels.JobLogs.JobLogsGridPanelViewMod
 0122    "Уведомления Ozon", "fa-bell text-primary", "Отправление, тип, ошибка…",
 0123    "Статусы: Received — принято, Processed — применено к заказу, Skipped — тип не обрабатывается, Error — обработчик уп
 124
 125<div class="modal fade" id="jobLogsWebhookDetailModal" tabindex="-1">
 126    <div class="modal-dialog modal-xl modal-dialog-scrollable">
 127        <div class="modal-content">
 128            <div class="modal-header">
 129                <h5 class="modal-title">Webhook #<span id="jobLogsWebhookDetailId"></span></h5>
 130                <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
 131            </div>
 132            <div class="modal-body">
 133                <pre id="jobLogsWebhookDetailBody" class="job-logs-webhook-payload mb-0"></pre>
 134            </div>
 135        </div>
 136    </div>
 137</div>

Methods/Properties

ExecuteAsync()