From 08ef38ebeda85e21d4ece1d7a90146c98be351b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=94=D0=BC=D0=B8=D1=82=D1=80=D0=B8=D0=B9?= Date: Wed, 20 May 2026 19:23:58 +0300 Subject: [PATCH] =?UTF-8?q?fix(layout):=20topbar=20title=20=D0=B8=D0=B7=20?= =?UTF-8?q?route.meta.title=20=D0=B4=D0=BB=D1=8F=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D0=B0=D0=BD=D0=B8=D1=86=20=D0=B2=D0=BD=D0=B5=20sidebar-nav?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit AppLayout брал заголовок топбара только из sidebar navItems → /reminders и /import (которых нет в боковом меню) показывали fallback «Страница». Добавлен fallback на route.meta.title перед «Страница». TDD: AppLayout.spec.ts (RED→GREEN). Co-Authored-By: Claude Opus 4.7 (1M context) --- app/resources/js/layouts/AppLayout.vue | 8 +++++++- app/tests/Frontend/AppLayout.spec.ts | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 1 deletion(-) diff --git a/app/resources/js/layouts/AppLayout.vue b/app/resources/js/layouts/AppLayout.vue index 25a79502..2233c0b0 100644 --- a/app/resources/js/layouts/AppLayout.vue +++ b/app/resources/js/layouts/AppLayout.vue @@ -41,7 +41,13 @@ const navItems = computed(() => [ ]); const currentPageTitle = computed(() => { - return navItems.value.find((i) => i.to === route.path)?.title ?? 'Страница'; + // Сначала короткий title из sidebar-nav (Дашборд/Сделки/…), затем — route.meta.title + // для страниц вне sidebar (Напоминания, Импорт данных), и только потом fallback. + return ( + navItems.value.find((i) => i.to === route.path)?.title ?? + (route.meta.title as string | undefined) ?? + 'Страница' + ); }); async function loadNotifications(): Promise { diff --git a/app/tests/Frontend/AppLayout.spec.ts b/app/tests/Frontend/AppLayout.spec.ts index 691330d6..3a54e1af 100644 --- a/app/tests/Frontend/AppLayout.spec.ts +++ b/app/tests/Frontend/AppLayout.spec.ts @@ -59,6 +59,13 @@ const mountAppLayout = async (path = '/dashboard', user: AuthUser | null = mockU { path: '/billing', component: { template: '
billing
' } }, { path: '/reports', component: { template: '
reports
' } }, { path: '/settings', component: { template: '
settings
' } }, + // Не в sidebar nav, но имеют meta.title — topbar должен брать title оттуда. + { + path: '/reminders', + component: { template: '
reminders
' }, + meta: { title: 'Напоминания' }, + }, + { path: '/import', component: { template: '
import
' }, meta: { title: 'Импорт данных' } }, ], }); await router.push(path); @@ -110,6 +117,18 @@ describe('AppLayout.vue', () => { expect(wrapper.text()).toContain('Дашборд'); }); + it('topbar title для страницы вне sidebar nav берётся из route.meta.title (Напоминания)', async () => { + const wrapper = await mountAppLayout('/reminders'); + // Напоминания нет в sidebar nav (см. тест выше) — title должен прийти из meta, не «Страница». + expect(wrapper.text()).toContain('Напоминания'); + expect(wrapper.text()).not.toContain('Страница'); + }); + + it('topbar title для /import берётся из route.meta.title (Импорт данных)', async () => { + const wrapper = await mountAppLayout('/import'); + expect(wrapper.text()).toContain('Импорт данных'); + }); + it('user-chip показывает initials и shortName из store user', async () => { const wrapper = await mountAppLayout(); const text = wrapper.text();