< Summary

Information
Class: OzonOrdersWeb.WebServices.Sidebar.SidebarNode
Assembly: OzonOrdersWeb
File(s): /home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Sidebar/SidebarNavigationCatalog.cs
Line coverage
90%
Covered lines: 9
Uncovered lines: 1
Coverable lines: 10
Total lines: 203
Line coverage: 90%
Branch coverage
N/A
Covered branches: 0
Total branches: 0
Branch coverage: N/A
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_Id()100%11100%
get_Title()100%11100%
get_Icon()100%11100%
get_Href()100%11100%
get_Keywords()100%11100%
get_BadgeId()100%210%
get_External()100%11100%
get_Children()100%11100%
get_IsLeaf()100%11100%

File(s)

/home/runner/work/Studio2Prod/Studio2Prod/OzonOrdersWeb/WebServices/Sidebar/SidebarNavigationCatalog.cs

#LineLine coverage
 1namespace OzonOrdersWeb.WebServices.Sidebar;
 2
 3/// <summary>Узел бокового меню: группа (уровень 0), подгруппа (уровень 1) или ссылка.</summary>
 1034public sealed record SidebarNode(
 2935    string Id,
 1196    string Title,
 887    string Icon,
 4928    string? Href = null,
 449    string? Keywords = null,
 010    string? BadgeId = null,
 10911    bool External = false,
 42812    IReadOnlyList<SidebarNode>? Children = null)
 13{
 22314    public bool IsLeaf => Href is not null;
 15}
 16
 17/// <summary>
 18/// Дерево бокового меню. Идентификаторы узлов стабильны — по ним пользовательские настройки
 19/// (избранное, порядок, свёрнутые группы) хранятся в <c>UserSidebarSettings</c>; переименование
 20/// или перенос пункта не теряет их, а удаление узла просто делает его настройки невидимыми.
 21/// </summary>
 22public static class SidebarNavigationCatalog
 23{
 24    private static readonly IReadOnlyList<SidebarNode> Common = new[]
 25    {
 26        new SidebarNode("orders", "Заказы", "fa-table", Children: new[]
 27        {
 28            new SidebarNode("orders.grid", "Таблица заказов", "fa-table-cells", "/Studio2/OrdersGrid", "grid ag-grid таб
 29            new SidebarNode("orders.list", "Список заказов", "fa-list", "/Studio2/Orders", BadgeId: "sidebar-order-contr
 30            new SidebarNode("orders.upload", "Загрузка заказов", "fa-cloud-upload-alt", Children: new[]
 31            {
 32                new SidebarNode("orders.upload.api", "Из API / файла", "fa-cloud-arrow-down", "/Studio2/Orders/Upload"),
 33                new SidebarNode("orders.upload.file", "Только файл", "fa-file-arrow-up", "/Studio2/Orders/UploadFile"),
 34                new SidebarNode("orders.upload.percentage", "Проценка из отчёта Ozon", "fa-percent", "/Studio2/Percentag
 35            }),
 36            new SidebarNode("orders.work", "Работа с заказом", "fa-pen-to-square", Children: new[]
 37            {
 38                new SidebarNode("orders.history", "История заказов", "fa-clock-rotate-left", "/Studio2/OrderHistory"),
 39                new SidebarNode("orders.control", "Контроль заказов", "fa-list-check", "/Studio2/OrderControl"),
 40                new SidebarNode("orders.labels", "Этикетки", "fa-tags", "/Studio2/Labels"),
 41                new SidebarNode("orders.assembly", "Лист подбора", "fa-clipboard-list", "/Studio2/AssemblyList"),
 42                new SidebarNode("orders.assembly.keys", "Ключи доступа к листам", "fa-key", "/Studio2/AssemblyListAccess
 43            }),
 44            new SidebarNode("orders.docs", "Документы и операции", "fa-file-invoice", Children: new[]
 45            {
 46                new SidebarNode("orders.transactions", "Журнал документов", "fa-book", "/Studio2/Transaction"),
 47                new SidebarNode("orders.transaction.jobs", "Задания транзакций", "fa-diagram-project", "/Studio2/Transac
 48                new SidebarNode("orders.time.tracking", "Трекинг времени", "fa-stopwatch", "/Studio2/TransactionTimeTrac
 49            }),
 50            new SidebarNode("orders.returns", "Возвраты и архив", "fa-box-archive", Children: new[]
 51            {
 52                new SidebarNode("orders.archive", "Архив заказов", "fa-box-archive", "/Studio2/OrderArchive"),
 53                new SidebarNode("orders.returns.ozon", "Возвраты Ozon", "fa-rotate-left", "/Studio2/OrderReturns"),
 54                new SidebarNode("orders.returns.journal", "Журнал возвратов", "fa-receipt", "/Studio2/Orders/Returns"),
 55                new SidebarNode("orders.returns.ozon.external", "Возвраты озон", "fa-arrow-up-right-from-square", "https
 56            }),
 57        }),
 58        new SidebarNode("purchases", "Закупки и склады", "fa-cart-shopping", Children: new[]
 59        {
 60            new SidebarNode("purchases.cart", "Заказы и корзины поставщиков", "fa-cart-shopping", "/Studio2/SupplierCart
 61            new SidebarNode("purchases.bitrix.stock", "Остатки 1С → Ozon", "fa-boxes-stacked", "/Studio2/BitrixStock?tab
 62            new SidebarNode("purchases.warehouse.stock", "Остатки склада", "fa-warehouse", "/Studio2/WarehouseStock"),
 63            new SidebarNode("purchases.onec.stock", "Остатки 1С по складам", "fa-pallet", "/Studio2/OneCStock", "1с odat
 64            new SidebarNode("purchases.match.files", "Сравнение файлов", "fa-code-compare", "/Studio2/MatchFileData"),
 65            new SidebarNode("purchases.interparts.currency", "Курсы Interparts", "fa-coins", "/Studio2/InterpartsSutCurr
 66            new SidebarNode("purchases.interparts.access", "Доступ к складам Interparts", "fa-warehouse", "/Studio2/Inte
 67        }),
 68        new SidebarNode("settlements", "Взаиморасчёты", "fa-scale-balanced", "/Settlements", "взаиморасчеты поставщики с
 69        new SidebarNode("analytics", "Аналитика и коммуникации", "fa-chart-line", Children: new[]
 70        {
 71            new SidebarNode("analytics.products", "Анализ продуктов", "fa-chart-pie", "/Studio2/ProductAnalysis"),
 72            new SidebarNode("analytics.prices", "История цен", "fa-chart-line", "/Studio2/PriceHistory"),
 73            new SidebarNode("analytics.ozon.chat", "Чаты Ozon", "fa-comments", "/Studio2/OzonChat", BadgeId: "sidebar-oz
 74            new SidebarNode("analytics.ai", "AI Ассистент", "fa-robot", "/Studio2/AiAssistant"),
 75        }),
 76        new SidebarNode("integrations", "Интеграции", "fa-plug", Children: new[]
 77        {
 78            new SidebarNode("integrations.onec", "1С", "fa-database", Children: new[]
 79            {
 80                new SidebarNode("integrations.onec.fresh", "1С Fresh", "fa-database", "/OneCFresh/Home"),
 81                new SidebarNode("integrations.onec.m2", "М2 Проект", "fa-arrow-up-right-from-square", "https://1c.mpsupe
 82            }),
 83            new SidebarNode("integrations.mail", "Почта и файлы", "fa-envelope-open-text", Children: new[]
 84            {
 85                new SidebarNode("integrations.mail.results", "Импорт заказов из почты", "fa-inbox", "/Studio2/EmailRouti
 86                new SidebarNode("integrations.mail.rules", "Правила импорта", "fa-filter", "/Studio2/EmailRoutingRules")
 87                new SidebarNode("integrations.mail.scheduler", "Планировщик импорта", "fa-calendar-days", "/Studio2/Emai
 88                new SidebarNode("integrations.files.records", "Записи загрузки файлов", "fa-file-lines", "/Studio2/FileU
 89                new SidebarNode("integrations.files.mappings", "Сопоставления Excel / CSV", "fa-table-columns", "/Studio
 90            }),
 91            new SidebarNode("integrations.feeds", "Фиды", "fa-chart-line", Children: new[]
 92            {
 93                new SidebarNode("integrations.feeds.stat", "Фиды", "fa-chart-line", "/Studio2/FidStat"),
 94                new SidebarNode("integrations.feeds.links", "Связи с фидом", "fa-link", "/Studio2/FidSupplierLink"),
 95            }),
 96            new SidebarNode("integrations.ozon", "Ozon", "fa-store", Children: new[]
 97            {
 98                new SidebarNode("integrations.ozon.webhooks", "Push-уведомления Ozon", "fa-bell", "/Studio2/OzonWebhookL
 99                new SidebarNode("integrations.ozon.clients", "Клиенты Ozon", "fa-users", "/Studio2/OzonClients"),
 100            }),
 101            new SidebarNode("integrations.suppliers", "Поставщики API", "fa-truck-fast", Children: new[]
 102            {
 103                new SidebarNode("integrations.suppliers.settings", "Настройки API-поставщиков", "fa-sliders", "/Studio2/
 104                new SidebarNode("integrations.suppliers.audit", "Логи запросов API", "fa-file-waveform", "/Studio2/ApiSu
 105                new SidebarNode("integrations.suppliers.consoles", "Консоли поставщиков", "fa-terminal", "/Armtek", "кон
 106            }),
 107        }),
 108    };
 109
 110    private static readonly IReadOnlyList<SidebarNode> AdminOnly = new[]
 111    {
 112        new SidebarNode("catalogs", "Справочники", "fa-book-open", Children: new[]
 113        {
 114            new SidebarNode("catalogs.goods", "Товары и контрагенты", "fa-box", Children: new[]
 115            {
 116                new SidebarNode("catalogs.products", "Товары", "fa-box", "/Studio2/Products"),
 117                new SidebarNode("catalogs.suppliers", "Поставщики", "fa-truck", "/Studio2/Supplier"),
 118                new SidebarNode("catalogs.manufacturers", "Производители Ozon", "fa-industry", "/Studio2/Manufacturers")
 119                new SidebarNode("catalogs.producers", "Производители ET", "fa-industry", "/Studio2/Producers"),
 120                new SidebarNode("catalogs.excluded.articles", "Исключённые артикулы", "fa-ban", "/Studio2/ExcludedArticl
 121            }),
 122            new SidebarNode("catalogs.warehouses", "Склады", "fa-warehouse", Children: new[]
 123            {
 124                new SidebarNode("catalogs.warehouse", "Склады", "fa-warehouse", "/Studio2/Warehouse"),
 125                new SidebarNode("catalogs.warehouse.mapping", "Связи складов", "fa-shuffle", "/Studio2/WarehouseMapping"
 126                new SidebarNode("catalogs.warehouse.excluded", "Исключённые склады Bitrix", "fa-circle-minus", "/Studio2
 127            }),
 128            new SidebarNode("catalogs.statuses", "Статусы", "fa-tag", Children: new[]
 129            {
 130                new SidebarNode("catalogs.status.app", "Статусы заказов", "fa-tag", "/Studio2/AppStatus"),
 131                new SidebarNode("catalogs.status.transitions", "Переходы статусов", "fa-arrow-right-arrow-left", "/Studi
 132                new SidebarNode("catalogs.status.supplier", "Статусы поставщиков", "fa-tags", "/Studio2/SupplierStatus")
 133                new SidebarNode("catalogs.status.client", "Статусы клиентов", "fa-user-tag", "/Studio2/ClientStatus"),
 134            }),
 135            new SidebarNode("catalogs.expense.types", "Типы расходов", "fa-wallet", "/Studio2/ExpenseType"),
 136        }),
 137        new SidebarNode("admin", "Администрирование", "fa-user-shield", Children: new[]
 138        {
 139            new SidebarNode("admin.center", "Центр администрирования", "fa-user-shield", "/Admin/Home/Index"),
 140            new SidebarNode("admin.access.profiles", "Профили доступа", "fa-user-lock", "/Studio2/AccessProfiles"),
 141            new SidebarNode("admin.data.scopes", "Наборы областей данных", "fa-filter", "/Admin/DataScopes/Index"),
 142            new SidebarNode("admin.partners", "Кабинет партнёров", "fa-handshake", "/PartnerOffice/Partners", "партнёры 
 143            new SidebarNode("admin.job.logs", "Журнал задач", "fa-clipboard-list", "/Studio2/JobLogs", BadgeId: "sidebar
 144            new SidebarNode("admin.config", "Конфигурация и база данных", "fa-screwdriver-wrench", "/Studio2/Config/Logi
 145        }),
 146        new SidebarNode("system", "Система", "fa-server", Children: new[]
 147        {
 148            new SidebarNode("system.hangfire.stats", "Статистика Hangfire", "fa-chart-bar", "/Studio2/HangfireQueue"),
 149            new SidebarNode("system.hangfire", "Задачи Hangfire", "fa-tasks", "/Hangfire", External: true),
 150            new SidebarNode("system.autoload", "Автозагрузка", "fa-robot", "/Studio2/Job"),
 151        }),
 152    };
 153
 154    /// <summary>
 155    /// Меню раздела /Admin (_AdminSidebar): своё дерево, настройки пользователя — под префиксом
 156    /// <see cref="AdminKeyPrefix"/>, чтобы избранное и порядок не смешивались с меню Studio2.
 157    /// </summary>
 158    public static readonly IReadOnlyList<SidebarNode> Admin = new[]
 159    {
 160        new SidebarNode("adm.main", "Основное", "fa-gauge", Children: new[]
 161        {
 162            new SidebarNode("adm.home", "Обзор", "fa-gauge", "/Admin/Home/Index", "админка панель обзор kpi"),
 163            new SidebarNode("adm.studio2", "В основное приложение", "fa-arrow-up-right-from-square", "/Studio2/OrdersGri
 164        }),
 165        new SidebarNode("adm.access", "Права доступа", "fa-user-shield", Children: new[]
 166        {
 167            new SidebarNode("adm.roles", "Роли", "fa-id-badge", "/Admin/Roles/Index", "роли матрица права страницы поля"
 168            new SidebarNode("adm.users", "Пользователи", "fa-users", "/Admin/Users/Index", "пользователи вход одобрение 
 169        }),
 170        new SidebarNode("adm.registry", "Реестры", "fa-layer-group", Children: new[]
 171        {
 172            new SidebarNode("adm.pages", "Страницы", "fa-window-restore", "/Admin/Pages/Index", "страницы реестр синхрон
 173            new SidebarNode("adm.fields", "Колонки заказов", "fa-table-columns", "/Admin/Fields/Index", "поля колонки or
 174            new SidebarNode("adm.scopes", "Наборы данных", "fa-filter", "/Admin/DataScopes/Index", "наборы данных data s
 175        }),
 176        new SidebarNode("adm.control", "Контроль", "fa-clipboard-check", Children: new[]
 177        {
 178            new SidebarNode("adm.audit", "Журнал изменений", "fa-book", "/Admin/AuditLog/Index", "аудит журнал изменений
 179            new SidebarNode("adm.order.control", "Требует действий", "fa-bell", "/Studio2/OrderControl"),
 180            new SidebarNode("adm.order.rules", "Правила SLA", "fa-sliders", "/Studio2/OrderControl/Rules"),
 181        }),
 182    };
 183
 184    /// <summary>Префикс ключей настроек меню /Admin в <c>UserSidebarSettings</c>.</summary>
 185    public const string AdminKeyPrefix = "admin.";
 186
 187    /// <summary>Дерево для пользователя: администраторы видят дополнительные группы.</summary>
 188    public static IReadOnlyList<SidebarNode> For(bool isAdmin) =>
 189        isAdmin ? Common.Concat(AdminOnly).ToArray() : Common;
 190
 191    /// <summary>Все идентификаторы узлов (для валидации сохраняемых настроек).</summary>
 192    public static IReadOnlySet<string> AllIds { get; } = Flatten(Common.Concat(AdminOnly)).Select(n => n.Id).ToHashSet(S
 193
 194    public static IEnumerable<SidebarNode> Flatten(IEnumerable<SidebarNode> nodes)
 195    {
 196        foreach (var node in nodes)
 197        {
 198            yield return node;
 199            if (node.Children is null) continue;
 200            foreach (var child in Flatten(node.Children)) yield return child;
 201        }
 202    }
 203}