From 39455a96ede2e727adf847b8e2f8f9ff97f6b3cc Mon Sep 17 00:00:00 2001 From: Timothy Date: Tue, 7 Jul 2026 12:11:11 +0200 Subject: [PATCH] =?UTF-8?q?feat(web):=20Classic=20UI=20link=20in=20Setting?= =?UTF-8?q?s=20=E2=86=92=20System=20(#147)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a discoverable "Open Classic UI" link in the SPA's Settings → System About card, pointing at /system/health (a real full-page navigation, not the SPA's pushState router), so un-migrated Blazor-only admin screens stay reachable now that root / redirects to the SPA. Also add a lightweight "Opens in ChicoryTV" tooltip cue (small icon) on the Blazor sidebar's redirecting MudNavLink entries (per LegacyUiRedirects.Map), so it's clear before clicking which sidebar entries leave the Blazor UI vs. stay in it. Co-Authored-By: Claude Fable 5 --- ErsatzTV/Locals/Shared/MainLayout.resx | 3 +++ ErsatzTV/Shared/MainLayout.razor | 30 +++++++++++++++++--------- web/src/App.test.tsx | 9 ++++++++ web/src/screens/SettingsScreen.tsx | 6 ++++++ 4 files changed, 38 insertions(+), 10 deletions(-) diff --git a/ErsatzTV/Locals/Shared/MainLayout.resx b/ErsatzTV/Locals/Shared/MainLayout.resx index 67110bc83..2b334293a 100644 --- a/ErsatzTV/Locals/Shared/MainLayout.resx +++ b/ErsatzTV/Locals/Shared/MainLayout.resx @@ -141,6 +141,9 @@ XMLTV + + Opens in ChicoryTV + Support diff --git a/ErsatzTV/Shared/MainLayout.razor b/ErsatzTV/Shared/MainLayout.razor index 1373fd51e..41232a333 100644 --- a/ErsatzTV/Shared/MainLayout.razor +++ b/ErsatzTV/Shared/MainLayout.razor @@ -117,7 +117,7 @@ { - @StringLocalizer["ButtonChannels"] + @StringLocalizer["ButtonChannels"]@ChicoryCue @StringLocalizer["ButtonFFmpegProfiles"] @StringLocalizer["ButtonWatermarks"] @@ -127,7 +127,7 @@ @StringLocalizer["ButtonMediaSourcesPlex"] - @StringLocalizer["ButtonMediaLibraries"] + @StringLocalizer["ButtonMediaLibraries"]@ChicoryCue @StringLocalizer["ButtonMediaTrash"] @StringLocalizer["ButtonMediaTvShows"] @StringLocalizer["ButtonMediaMovies"] @@ -161,7 +161,7 @@ } - @StringLocalizer["ButtonSchedulingSchedules"] + @StringLocalizer["ButtonSchedulingSchedules"]@ChicoryCue @StringLocalizer["ButtonSchedulingBlocks"] @StringLocalizer["ButtonSchedulingTemplates"] @StringLocalizer["ButtonSchedulingDecos"] @@ -180,17 +180,18 @@ { @StringLocalizer["ButtonSchedulingPlayouts"] } + @ChicoryCue - @StringLocalizer["ButtonSettingsFFmpeg"] - @StringLocalizer["ButtonSettingsLogging"] - @StringLocalizer["ButtonSettingsHdHomeRun"] - @StringLocalizer["ButtonSettingsScanner"] - @StringLocalizer["ButtonSettingsPlayout"] - @StringLocalizer["ButtonSettingsUi"] - @StringLocalizer["ButtonSettingsXmltv"] + @StringLocalizer["ButtonSettingsFFmpeg"]@ChicoryCue + @StringLocalizer["ButtonSettingsLogging"]@ChicoryCue + @StringLocalizer["ButtonSettingsHdHomeRun"]@ChicoryCue + @StringLocalizer["ButtonSettingsScanner"]@ChicoryCue + @StringLocalizer["ButtonSettingsPlayout"]@ChicoryCue + @StringLocalizer["ButtonSettingsUi"]@ChicoryCue + @StringLocalizer["ButtonSettingsXmltv"]@ChicoryCue @@ -260,6 +261,15 @@ @code { + // Lightweight cue (ersatztv#147): marks nav entries that 302-redirect into the + // ChicoryTV SPA (see LegacyUiRedirects.Map) so it's clear before clicking that the + // entry leaves this Blazor UI. Non-redirecting entries in the same MudNavGroup are + // left bare. + private RenderFragment ChicoryCue => + @ + + ; + private static readonly string InfoVersion = Assembly.GetEntryAssembly().GetCustomAttribute()?.InformationalVersion ?? "unknown"; private static readonly string BuildConfiguration = Assembly.GetEntryAssembly().GetCustomAttribute()?.Configuration?.ToLower() ?? "unset"; diff --git a/web/src/App.test.tsx b/web/src/App.test.tsx index 866ab5736..01ed499d0 100644 --- a/web/src/App.test.tsx +++ b/web/src/App.test.tsx @@ -2728,6 +2728,15 @@ describe('Settings screen (#93)', () => { expect(await screen.findByText('Local')).toBeInTheDocument(); }); + it('shows a Classic UI link to the legacy Blazor app in the System pane (#147)', async () => { + mockDashboardApi(); + await openSettings(); + fireEvent.click(await screen.findByRole('button', { name: /^System/ })); + + const link = await screen.findByRole('link', { name: /Open Classic UI/ }); + expect(link).toHaveAttribute('href', '/system/health'); + }); + it('renders and stays editable when media sources (tier-2 reference data) fail to load', async () => { mockDashboardApi({ mediaSourcesFailuresBeforeSuccess: 99 }); await openSettings(); diff --git a/web/src/screens/SettingsScreen.tsx b/web/src/screens/SettingsScreen.tsx index fb2f9f43c..e087cb62f 100644 --- a/web/src/screens/SettingsScreen.tsx +++ b/web/src/screens/SettingsScreen.tsx @@ -854,6 +854,12 @@ function SystemPane({ Open Dashboard + + + Open Classic UI + + );