< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Admin_Views_Users_Index
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Admin/Views/Users/Index.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 10
Coverable lines: 10
Total lines: 93
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 10
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%110100%
<ExecuteAsync()100%210%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Admin/Views/Users/Index.cshtml

#LineLine coverage
 1@model UsersIndexVm
 2@{
 03    var json = new System.Text.Json.JsonSerializerOptions(System.Text.Json.JsonSerializerDefaults.Web);
 4}
 5
 6<section class="admin-hero">
 7    <h1>Пользователи</h1>
 8    <p class="subtitle">Управление входом, ролями и доступом.</p>
 9    <p class="subtitle-help">Отображаются профиль, статусы блокировки и одобрения входа.</p>
 10</section>
 11
 12<nav class="admin-quick-links" aria-label="Связанные разделы">
 13    <a asp-area="Admin" asp-controller="Roles" asp-action="Index"><i class="bi bi-person-badge"></i>Роли</a>
 14    <a asp-area="Admin" asp-controller="DataScopes" asp-action="Index"><i class="bi bi-funnel"></i>Наборы данных</a>
 15    <a asp-area="Admin" asp-controller="AuditLog" asp-action="Index"><i class="bi bi-journal-text"></i>Аудит</a>
 16</nav>
 17
 18<section class="admin-intro">
 19    <i class="bi bi-info-circle"></i>
 20    <div>Статус «Доступ» вычисляется по двум признакам: подтверждение email и одобрение администратором. Двойной клик по
 21</section>
 22
 23<div class="admin-toolbar admin-surface">
 24    <div class="bsx-dir-stats">
 025        <span class="bsx-dir-stat">Всего <b>@Model.Items.Count</b></span>
 026        <span class="bsx-dir-stat bsx-dir-stat--warn">Не одобрены <b>@Model.Items.Count(u => !(u.EmailConfirmed && u.IsA
 027        <span class="bsx-dir-stat">Заблокированы <b>@Model.Items.Count(u => u.IsLocked)</b></span>
 28    </div>
 029    <a asp-action="Create" asp-route-q="@Model.Query" class="btn btn-primary btn-sm"><i class="bi bi-person-plus"></i> С
 30</div>
 31
 032@await Html.PartialAsync("~/Areas/Studio2/Views/Shared/_BsxDirectoryGrid.cshtml", new BsxDirectoryGridViewModel("admUser
 033<script type="application/json" id="admUsersData">@Html.Raw(System.Text.Json.JsonSerializer.Serialize(AdminGridRows.User
 34
 35@section Scripts {
 36    <script>
 37        (function () {
 38            const A = window.AdminGrid, D = window.BsxDirectory, esc = A.esc;
 039            const editUrl = id => '@Url.Action("Edit")/' + encodeURIComponent(id);
 040            const lockUrl = id => '@Url.Action("Lock")/' + encodeURIComponent(id);
 041            const unlockUrl = id => '@Url.Action("Unlock")/' + encodeURIComponent(id);
 42            const grid = A.grid({
 43                key: 'admUsers', prefix: 'admUsers', rows: A.data('admUsersData'),
 44                rowUrl: r => editUrl(r.id),
 45                columnDefs: [
 46                    {
 47                        colId: 'user', field: 'displayName', headerName: 'Пользователь', minWidth: 220, flex: 2,
 48                        getQuickFilterText: p => [p.data.displayName, p.data.secondaryName].join(' '),
 49                        cellRenderer: p => {
 50                            const r = p.data; if (!r) return '';
 51                            const avatar = r.avatarUrl
 52                                ? '<img src="' + esc(r.avatarUrl) + '" alt="" class="admin-user-avatar" referrerpolicy="
 53                                : '<span class="admin-user-avatar-fallback">' + esc(r.initials) + '</span>';
 54                            return '<span class="admin-user">' + avatar + '<span class="bsx-cell-stack"><b>' + esc(r.dis
 55                                (r.secondaryName ? '<small class="bsx-muted">' + esc(r.secondaryName) + '</small>' : '')
 56                        }
 57                    },
 58                    { colId: 'email', field: 'email', headerName: 'Email', minWidth: 200, flex: 2 },
 59                    D.setCol({
 60                        colId: 'roles', headerName: 'Роли', minWidth: 200, flex: 2, autoHeight: true,
 61                        valueGetter: p => p.data ? (p.data.roles || []).join(', ') : '',
 62                        cellRenderer: p => {
 63                            const roles = p.data ? p.data.roles || [] : [];
 64                            return roles.length ? '<span class="admin-chips">' + roles.map(r => D.tone(r, 'accent')).joi
 65                        }
 66                    }),
 67                    D.numCol({ colId: 'overrideCount', field: 'overrideCount', headerName: 'Override', width: 110, value
 68                    D.setCol({
 69                        colId: 'isLocked', headerName: 'Блокировка', width: 140,
 70                        valueGetter: p => p.data ? String(p.data.isLocked) : '',
 71                        filterParams: { labels: { 'true': 'Заблокирован', 'false': 'Активен' } },
 72                        cellRenderer: p => p.value === 'true' ? D.tone('Заблокирован', 'danger') : D.tone('Активен', 'su
 73                    }),
 74                    D.setCol({
 75                        colId: 'isApproved', headerName: 'Доступ', width: 130,
 76                        valueGetter: p => p.data ? String(p.data.isApproved) : '',
 77                        filterParams: { labels: { 'true': 'Одобрен', 'false': 'Не одобрен' } },
 78                        cellRenderer: p => p.value === 'true' ? D.tone('Одобрен', 'success') : D.tone('Не одобрен', 'war
 79                    }),
 80                    D.numCol({ colId: 'accessFailedCount', field: 'accessFailedCount', headerName: 'Вход (ошибок)', widt
 81                    D.actionsCol(r => [
 82                        { icon: 'fa-pen', title: 'Настроить', label: 'Настроить', kind: 'edit', href: editUrl(r.id) },
 83                        r.isLocked
 84                            ? { icon: 'fa-lock-open', title: 'Снять блокировку и сбросить неудачные попытки входа', kind
 85                                onClick: row => A.confirmPost(unlockUrl(row.id), {}, { title: 'Разблокировать пользовате
 86                            : { icon: 'fa-lock', title: 'Заблокировать вход', kind: 'danger',
 87                                onClick: row => A.confirmPost(lockUrl(row.id), {}, { title: 'Заблокировать пользователя'
 88                    ], { width: 170 })
 89                ]
 90            });
 91        })();
 92    </script>
 93}

Methods/Properties

ExecuteAsync()
<ExecuteAsync()