Add the SPA screens over the new detail/info/image endpoints:
- Detail pages at /app/media/{movies|shows|seasons|artists}/{id}. MediaBrowseScreen
cards for movies/shows/artists (and season/show drill-in cards) navigate to them.
Shows list seasons -> seasons list episodes -> artists list music videos, each via
the browse parentId drill-in, paged. Layout: fanart/poster, title/year/plot, chip
lists, cast row, movie path + FileNotFound/Unavailable warnings. A "Media Info"
dialog (streams + chapters) backs onto GET /api/media-items/{id}/info. Add-to-
collection/playlist deferred to #153/#155 (TODO left in code).
- Image folder browser at /app/media/images/browser: lazy expandable tree, per-folder
image/subfolder counts + duration, edit dialog (PUT set/clear), and a per-folder
search link (library_folder_id:{id}). Reachable via a "Folder Browser" button on the
Images browse view.
New /app/media sub-paths are owned by a MediaRouteScreen wrapper that tracks pathname
locally + listens for popstate (App-level routing returns the same 'media' route object
for base and sub-paths). Client modules web/src/api/mediaDetail.ts + imageFolders.ts,
typed via the generated v1.d.ts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
29 lines
1.2 KiB
TypeScript
29 lines
1.2 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { parseMediaSubRoute } from './routing';
|
|
|
|
describe('parseMediaSubRoute', () => {
|
|
it('returns null for the base media path', () => {
|
|
expect(parseMediaSubRoute('/app/media')).toBeNull();
|
|
expect(parseMediaSubRoute('/app/media/')).toBeNull();
|
|
});
|
|
|
|
it('parses the four detail kinds', () => {
|
|
expect(parseMediaSubRoute('/app/media/movies/5')).toEqual({ id: 5, kind: 'movie' });
|
|
expect(parseMediaSubRoute('/app/media/shows/6')).toEqual({ id: 6, kind: 'show' });
|
|
expect(parseMediaSubRoute('/app/media/seasons/7')).toEqual({ id: 7, kind: 'season' });
|
|
expect(parseMediaSubRoute('/app/media/artists/8')).toEqual({ id: 8, kind: 'artist' });
|
|
});
|
|
|
|
it('parses the image browser path', () => {
|
|
expect(parseMediaSubRoute('/app/media/images/browser')).toEqual({ kind: 'images' });
|
|
});
|
|
|
|
it('rejects unknown kinds and non-numeric ids', () => {
|
|
expect(parseMediaSubRoute('/app/media/widgets/5')).toBeNull();
|
|
expect(parseMediaSubRoute('/app/media/movies/abc')).toBeNull();
|
|
expect(parseMediaSubRoute('/app/media/movies/0')).toBeNull();
|
|
expect(parseMediaSubRoute('/app/media/movies')).toBeNull();
|
|
expect(parseMediaSubRoute('/app/media/movies/5/extra')).toBeNull();
|
|
});
|
|
});
|