< Summary

Information
Class: AspNetCoreGeneratedDocument.Areas_Admin_Views_DataScopes_FromTemplate
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Admin/Views/DataScopes/FromTemplate.cshtml
Line coverage
0%
Covered lines: 0
Uncovered lines: 15
Coverable lines: 15
Total lines: 187
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 62
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%2970540%
<ExecuteAsync()0%7280%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/Areas/Admin/Views/DataScopes/FromTemplate.cshtml

#LineLine coverage
 1@model OzonOrdersWeb.Areas.Admin.Models.DataScopeFromTemplateVm
 2
 3<section class="admin-hero">
 4    <h1>Создание набора из шаблона</h1>
 5    <p class="subtitle">Соберите ограничение данных с генерацией выражения.</p>
 6    <p class="subtitle-help">Проверьте код и название перед сохранением.</p>
 7</section>
 8
 9<nav class="admin-quick-links">
 10    <a asp-area="Admin" asp-controller="DataScopes" asp-action="Templates"><i class="bi bi-magic"></i>К шаблонам</a>
 11    <a asp-area="Admin" asp-controller="DataScopes" asp-action="Index"><i class="bi bi-funnel"></i>Реестр наборов</a>
 12    <a asp-area="Admin" asp-controller="Roles" asp-action="Index"><i class="bi bi-person-badge"></i>Роли</a>
 13</nav>
 14
 15<form asp-action="FromTemplate" method="post">
 016    @Html.AntiForgeryToken()
 17    <input type="hidden" asp-for="TemplateKey"/>
 18    <input type="hidden" asp-for="EntityName"/>
 19    <input type="hidden" asp-for="FkField"/>
 20    <input type="hidden" asp-for="TemplateDisplayName"/>
 21
 22    <div class="card mb-3">
 23        <div class="card-body d-flex align-items-start gap-3">
 24            <div class="template-icon">
 25                <i class="bi @(string.IsNullOrEmpty(Model.TemplateIcon) ? "bi-funnel" : Model.TemplateIcon)"></i>
 26            </div>
 27            <div class="flex-grow-1">
 028                <div class="fw-semibold">@Model.TemplateDisplayName</div>
 029                <div class="text-muted small">@Model.TemplateDescription</div>
 30                <div class="mt-2">
 031                    <span class="bsx-tone bsx-tone--muted">Сущность: <strong>@Model.EntityName</strong></span>
 032                    @if (Model.IsRangeTemplate)
 33                    {
 34                        <span class="bsx-tone bsx-tone--info">Диапазон</span>
 35                    }
 036                    <span class="bsx-tone bsx-tone--muted">Поле: <strong>@Model.FkField</strong></span>
 37                </div>
 38            </div>
 39            <a asp-action="Templates" class="btn btn-sm btn-outline-secondary"><i class="bi bi-arrow-left"></i> К шаблон
 40        </div>
 41    </div>
 42
 43    <div class="row g-3">
 44        <div class="col-lg-5">
 45            <div class="card h-100">
 46                <div class="card-header py-2"><strong>Параметры набора</strong></div>
 47                <div class="card-body">
 48                    <div class="mb-3">
 49                        <label asp-for="Code" class="form-label"></label>
 50                        <input asp-for="Code" class="form-control"/>
 51                        <span asp-validation-for="Code" class="text-danger small"></span>
 52                    </div>
 53                    <div class="mb-3">
 54                        <label asp-for="DisplayName" class="form-label"></label>
 55                        <input asp-for="DisplayName" class="form-control"/>
 56                        <span asp-validation-for="DisplayName" class="text-danger small"></span>
 57                    </div>
 58                    <div class="mb-3">
 59                        <label asp-for="Description" class="form-label"></label>
 60                        <textarea asp-for="Description" rows="2" class="form-control"></textarea>
 61                    </div>
 62                    <div class="form-check">
 63                        <input asp-for="IsActive" class="form-check-input"/>
 64                        <label class="form-check-label" asp-for="IsActive"></label>
 65                    </div>
 66                </div>
 67            </div>
 68        </div>
 69
 70        <div class="col-lg-7">
 71            <div class="card h-100">
 072                @if (Model.IsRangeTemplate)
 73                {
 74                    <div class="card-header py-2"><strong>Диапазон значений</strong></div>
 75                    <div class="card-body">
 76                        <p class="text-muted small">Можно указать одну границу: только мин., только макс. или обе.</p>
 77                        <div class="row g-2">
 78                            <div class="col-sm-6">
 79                                <label asp-for="MinValue" class="form-label">Минимум (включительно)</label>
 80                                <input asp-for="MinValue" class="form-control" type="text" inputmode="decimal" placehold
 81                                <span asp-validation-for="MinValue" class="text-danger small"></span>
 82                            </div>
 83                            <div class="col-sm-6">
 84                                <label asp-for="MaxValue" class="form-label">Максимум (включительно)</label>
 85                                <input asp-for="MaxValue" class="form-control" type="text" inputmode="decimal" placehold
 86                                <span asp-validation-for="MaxValue" class="text-danger small"></span>
 87                            </div>
 88                        </div>
 89                    </div>
 90                }
 91                else
 92                {
 93                    <div class="card-header py-2 d-flex align-items-center gap-2">
 94                        <strong>Выберите значения</strong>
 95                        <span class="bsx-tone bsx-tone--accent" id="selectedCount">0</span>
 96                        <span asp-validation-for="SelectedIds" class="text-danger small ms-2"></span>
 97                    </div>
 98                    <div class="card-body p-2">
 099                        @if (Model.Items.Count == 0)
 100                        {
 101                            <div class="text-center bsx-muted py-5">Справочник пуст</div>
 102                        }
 103                        else
 104                        {
 105                            <div id="admTemplateSelected" hidden></div>
 0106                            @await Html.PartialAsync("~/Areas/Studio2/Views/Shared/_BsxDirectoryGrid.cshtml", new BsxDir
 0107                                "Галка в заголовке отмечает все строки, видимые с учётом поиска и фильтров."))
 108                        }
 109                    </div>
 110                }
 111                <div class="card-footer small text-muted">
 112                    Результирующее выражение:
 113                    <code id="exprPreview" class="ms-1"></code>
 114                </div>
 115            </div>
 116        </div>
 117    </div>
 118
 119    <div class="mt-3 d-flex gap-2">
 120        <button type="submit" class="btn btn-primary"><i class="bi bi-save"></i> Создать набор</button>
 121        <a asp-action="Templates" class="btn btn-outline-secondary">Отмена</a>
 122    </div>
 123</form>
 124
 0125<script type="application/json" id="admTemplateItemsData">@Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.Item
 126
 127@section Scripts {
 128    <partial name="_ValidationScriptsPartial"/>
 129    <script>
 130        (function() {
 0131            const isRange = @(Model.IsRangeTemplate ? "true" : "false");
 0132            const fkField = @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.FkField));
 0133            const rangeIsDecimal = @(Model.RangeIsDecimal ? "true" : "false");
 134            const preview = document.getElementById('exprPreview');
 135            if (isRange) {
 136                const minEl = document.getElementById('rangeMin');
 137                const maxEl = document.getElementById('rangeMax');
 138                function numOrNull(s) {
 139                    s = (s || '').trim().replace(',', '.');
 140                    if (s === '') return null;
 141                    const n = Number(s);
 142                    return Number.isFinite(n) ? n : null;
 143                }
 144                function updateRangePreview() {
 145                    const a = minEl ? numOrNull(minEl.value) : null;
 146                    const b = maxEl ? numOrNull(maxEl.value) : null;
 147                    if (a == null && b == null) { preview.textContent = '—'; return; }
 148                    const parts = [fkField + ' != null'];
 149                    if (rangeIsDecimal) {
 150                        if (a != null) parts.push(fkField + ' >= ' + a);
 151                        if (b != null) parts.push(fkField + ' <= ' + b);
 152                    } else {
 153                        if (a != null) parts.push(fkField + ' >= ' + Math.trunc(a));
 154                        if (b != null) parts.push(fkField + ' <= ' + Math.trunc(b));
 155                    }
 156                    preview.textContent = '(' + parts.join(' && ') + ')';
 157                }
 158                minEl?.addEventListener('input', updateRangePreview);
 159                maxEl?.addEventListener('input', updateRangePreview);
 160                updateRangePreview();
 161                return;
 162            }
 163            const countEl = document.getElementById('selectedCount');
 164            function updatePreview(values) {
 165                countEl.textContent = values.length;
 166                if (values.length === 0) { preview.textContent = '—'; return; }
 167                const allNumeric = values.every(v => /^-?\d+$/.test(v));
 168                const parts = values.map(v => allNumeric
 169                    ? `${fkField} == ${v}`
 170                    : `${fkField} == "${v.replace(/"/g, '\\"')}"`);
 171                preview.textContent = '(' + parts.join(' || ') + ')';
 172            }
 173            const A = window.AdminGrid;
 174            A.selectionGrid({
 175                key: 'admTemplateItems', prefix: 'admTemplateItems',
 176                rows: A.data('admTemplateItemsData'),
 0177                selected: @Html.Raw(System.Text.Json.JsonSerializer.Serialize(Model.SelectedIds ?? Array.Empty<string>()
 178                inputName: 'SelectedIds', hiddenId: 'admTemplateSelected',
 179                onChange: updatePreview,
 180                columnDefs: [
 181                    { colId: 'name', field: 'name', headerName: 'Значение', minWidth: 240, flex: 3 },
 182                    { colId: 'id', field: 'id', headerName: 'ID', width: 120, cellClass: 'bsx-code', valueFormatter: p =
 183                ]
 184            });
 185        })();
 186    </script>
 187}

Methods/Properties

<ExecuteAsync()
<ExecuteAsync()