feat(web): Classic UI link in Settings → System (#147)
Build ErsatzTV Image / Build & test (.NET) (pull_request) Successful in 3m25s
Build ErsatzTV Image / EF migration integrity (SQLite + MySql) (pull_request) Successful in 3m23s
Build ErsatzTV Image / Build & push image (amd64) (pull_request) Has been skipped

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 <noreply@anthropic.com>
This commit is contained in:
2026-07-07 12:11:11 +02:00
co-authored by Claude Fable 5
parent 2362850559
commit 39455a96ed
4 changed files with 38 additions and 10 deletions
+3
View File
@@ -141,6 +141,9 @@
<data name="ButtonSettingsXmltv" xml:space="preserve">
<value>XMLTV</value>
</data>
<data name="ButtonOpensInChicoryTv" xml:space="preserve">
<value>Opens in ChicoryTV</value>
</data>
<data name="ButtonSupport" xml:space="preserve">
<value>Support</value>
</data>
+20 -10
View File
@@ -117,7 +117,7 @@
{
<MudDrawer @bind-Open="@_drawerIsOpen" Elevation="2" ClipMode="DrawerClipMode.Always">
<MudNavMenu>
<MudNavLink Href="channels">@StringLocalizer["ButtonChannels"]</MudNavLink>
<MudNavLink Href="channels">@StringLocalizer["ButtonChannels"]@ChicoryCue</MudNavLink>
<MudNavLink Href="ffmpeg">@StringLocalizer["ButtonFFmpegProfiles"]</MudNavLink>
<MudNavLink Href="watermarks">@StringLocalizer["ButtonWatermarks"]</MudNavLink>
<MudNavGroup Title="@StringLocalizer["ButtonMediaSources"]">
@@ -127,7 +127,7 @@
<MudNavLink Href="media/sources/plex">@StringLocalizer["ButtonMediaSourcesPlex"]</MudNavLink>
</MudNavGroup>
<MudNavGroup Title="@StringLocalizer["ButtonMedia"]">
<MudNavLink Href="media/libraries">@StringLocalizer["ButtonMediaLibraries"]</MudNavLink>
<MudNavLink Href="media/libraries">@StringLocalizer["ButtonMediaLibraries"]@ChicoryCue</MudNavLink>
<MudNavLink Href="media/trash">@StringLocalizer["ButtonMediaTrash"]</MudNavLink>
<MudNavLink Href="media/tv/shows">@StringLocalizer["ButtonMediaTvShows"]</MudNavLink>
<MudNavLink Href="media/movies">@StringLocalizer["ButtonMediaMovies"]</MudNavLink>
@@ -161,7 +161,7 @@
}
</TitleContent>
<ChildContent>
<MudNavLink Href="schedules">@StringLocalizer["ButtonSchedulingSchedules"]</MudNavLink>
<MudNavLink Href="schedules">@StringLocalizer["ButtonSchedulingSchedules"]@ChicoryCue</MudNavLink>
<MudNavLink Href="blocks">@StringLocalizer["ButtonSchedulingBlocks"]</MudNavLink>
<MudNavLink Href="templates">@StringLocalizer["ButtonSchedulingTemplates"]</MudNavLink>
<MudNavLink Href="decos">@StringLocalizer["ButtonSchedulingDecos"]</MudNavLink>
@@ -180,17 +180,18 @@
{
@StringLocalizer["ButtonSchedulingPlayouts"]
}
@ChicoryCue
</MudNavLink>
</ChildContent>
</MudNavGroup>
<MudNavGroup Title="@StringLocalizer["ButtonSettings"]">
<MudNavLink Href="settings/ffmpeg">@StringLocalizer["ButtonSettingsFFmpeg"]</MudNavLink>
<MudNavLink Href="settings/logging">@StringLocalizer["ButtonSettingsLogging"]</MudNavLink>
<MudNavLink Href="settings/hdhr">@StringLocalizer["ButtonSettingsHdHomeRun"]</MudNavLink>
<MudNavLink Href="settings/scanner">@StringLocalizer["ButtonSettingsScanner"]</MudNavLink>
<MudNavLink Href="settings/playout">@StringLocalizer["ButtonSettingsPlayout"]</MudNavLink>
<MudNavLink Href="settings/ui">@StringLocalizer["ButtonSettingsUi"]</MudNavLink>
<MudNavLink Href="settings/xmltv">@StringLocalizer["ButtonSettingsXmltv"]</MudNavLink>
<MudNavLink Href="settings/ffmpeg">@StringLocalizer["ButtonSettingsFFmpeg"]@ChicoryCue</MudNavLink>
<MudNavLink Href="settings/logging">@StringLocalizer["ButtonSettingsLogging"]@ChicoryCue</MudNavLink>
<MudNavLink Href="settings/hdhr">@StringLocalizer["ButtonSettingsHdHomeRun"]@ChicoryCue</MudNavLink>
<MudNavLink Href="settings/scanner">@StringLocalizer["ButtonSettingsScanner"]@ChicoryCue</MudNavLink>
<MudNavLink Href="settings/playout">@StringLocalizer["ButtonSettingsPlayout"]@ChicoryCue</MudNavLink>
<MudNavLink Href="settings/ui">@StringLocalizer["ButtonSettingsUi"]@ChicoryCue</MudNavLink>
<MudNavLink Href="settings/xmltv">@StringLocalizer["ButtonSettingsXmltv"]@ChicoryCue</MudNavLink>
</MudNavGroup>
<MudNavGroup Expanded="true">
<TitleContent>
@@ -260,6 +261,15 @@
</MudLayout>
@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 =>
@<MudTooltip Text="@StringLocalizer["ButtonOpensInChicoryTv"]">
<MudIcon Icon="@Icons.Material.Filled.OpenInNew" Size="Size.Small" Class="ml-1" Style="opacity:.55;vertical-align:text-bottom"/>
</MudTooltip>;
private static readonly string InfoVersion = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "unknown";
private static readonly string BuildConfiguration = Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyConfigurationAttribute>()?.Configuration?.ToLower() ?? "unset";
+9
View File
@@ -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();
+6
View File
@@ -854,6 +854,12 @@ function SystemPane({
Open Dashboard
</Button>
</Row>
<Row control={220} help="Collections, media browse/search, trakt, filler, watermarks, ffmpeg profiles, blocks/decos/templates, playout editors, logs and troubleshooting still live here." label="Classic UI">
<a className="ctv-button ctv-button-secondary ctv-button-sm" href="/system/health">
<span>Open Classic UI</span>
<ExternalLink aria-hidden="true" size={13} />
</a>
</Row>
</Card>
</Pane>
);