Fix warnings and update tracability
This commit is contained in:
@@ -67,9 +67,9 @@
|
||||
// Load related artists (by genre)
|
||||
try {
|
||||
if (artist.genres && artist.genres.length > 0) {
|
||||
const relatedResult = await repo.getItems(undefined, {
|
||||
const relatedResult = await repo.getItems(artist.id, {
|
||||
includeItemTypes: ["MusicArtist"],
|
||||
genreIds: artist.genres.slice(0, 2),
|
||||
genres: artist.genres.slice(0, 2),
|
||||
limit: 12,
|
||||
sortBy: "CommunityRating",
|
||||
sortOrder: "Descending"
|
||||
|
||||
@@ -297,7 +297,7 @@ describe.skip("Async Image Loading Pattern", () => {
|
||||
|
||||
const promises = items.map(item =>
|
||||
mockRepository.getImageUrl(item.id, "Primary")
|
||||
.then(url => imageUrls.set(item.id, url))
|
||||
.then((url: string) => imageUrls.set(item.id, url))
|
||||
.catch(() => imageUrls.set(item.id, ""))
|
||||
);
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- TRACES: UR-035 | JA-029 | DR-040, DR-044 -->
|
||||
<script lang="ts">
|
||||
import type { Person, PersonType } from "$lib/api/types";
|
||||
import { goto } from "$app/navigation";
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- TRACES: UR-035 | JA-029 | DR-040 -->
|
||||
<script lang="ts">
|
||||
import { goto } from "$app/navigation";
|
||||
import type { Person } from "$lib/api/types";
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
import ResultsCounter from "$lib/components/common/ResultsCounter.svelte";
|
||||
import CachedImage from "$lib/components/common/CachedImage.svelte";
|
||||
import { useServerReachabilityReload } from "$lib/composables/useServerReachabilityReload";
|
||||
import type { Genre, MediaItem } from "$lib/api/types";
|
||||
import type { Genre, MediaItem, ItemType } from "$lib/api/types";
|
||||
|
||||
/**
|
||||
* Generic genre browser supporting Movies, Music Albums, and TV Series
|
||||
@@ -20,7 +20,7 @@
|
||||
*/
|
||||
|
||||
export interface GenreConfig {
|
||||
itemTypes: string[]; // ["Movie"] or ["MusicAlbum"] or ["Series"]
|
||||
itemTypes: ItemType[]; // ["Movie"] or ["MusicAlbum"] or ["Series"]
|
||||
title: string; // "Movie Genres" or "Genres" or "TV Genres"
|
||||
backPath: string; // "/library" or "/library/music"
|
||||
genreIcon: string; // SVG path for genre icon
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
<!-- TRACES: UR-007, UR-029, UR-030 | DR-007, DR-032, DR-033 -->
|
||||
<script lang="ts">
|
||||
import { onMount } from "svelte";
|
||||
import { goto } from "$app/navigation";
|
||||
@@ -9,7 +10,7 @@
|
||||
import BackButton from "$lib/components/common/BackButton.svelte";
|
||||
import ResultsCounter from "$lib/components/common/ResultsCounter.svelte";
|
||||
import { useServerReachabilityReload } from "$lib/composables/useServerReachabilityReload";
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import type { MediaItem, Library, ItemType } from "$lib/api/types";
|
||||
import LibraryGrid from "./LibraryGrid.svelte";
|
||||
import TrackList from "./TrackList.svelte";
|
||||
|
||||
@@ -23,7 +24,7 @@
|
||||
*/
|
||||
|
||||
export interface MediaListConfig {
|
||||
itemType: string; // "MusicAlbum", "MusicArtist", "Playlist", "Audio"
|
||||
itemType: ItemType; // "MusicAlbum", "MusicArtist", "Playlist", "Audio"
|
||||
title: string; // "Albums", "Artists", "Playlists", "Tracks"
|
||||
backPath: string; // "/library/music"
|
||||
searchPlaceholder?: string;
|
||||
@@ -127,7 +128,7 @@
|
||||
|
||||
const searchPlaceholder = $derived(config.searchPlaceholder || `Search ${config.title.toLowerCase()}...`);
|
||||
|
||||
function handleItemClick(item: MediaItem) {
|
||||
function handleItemClick(item: MediaItem | Library) {
|
||||
// Navigate to detail page for browseable items
|
||||
goto(`/library/${item.id}`);
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
describe("Component Initialization", () => {
|
||||
it("should render with title and search bar", () => {
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -67,7 +67,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
|
||||
it("should load items on mount", async () => {
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -87,7 +87,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
|
||||
it("should display sort options", () => {
|
||||
const config = {
|
||||
itemType: "MusicAlbum",
|
||||
itemType: "MusicAlbum" as const,
|
||||
title: "Albums",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search albums...",
|
||||
@@ -115,7 +115,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
vi.useFakeTimers();
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -169,7 +169,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -215,7 +215,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -260,7 +260,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -309,7 +309,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "MusicAlbum",
|
||||
itemType: "MusicAlbum" as const,
|
||||
title: "Albums",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search albums...",
|
||||
@@ -349,7 +349,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -395,7 +395,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -433,7 +433,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "MusicAlbum",
|
||||
itemType: "MusicAlbum" as const,
|
||||
title: "Albums",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search albums...",
|
||||
@@ -479,7 +479,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -515,7 +515,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -558,7 +558,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
);
|
||||
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -581,7 +581,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
describe("Display Component Props", () => {
|
||||
it("should support grid display component", () => {
|
||||
const config = {
|
||||
itemType: "MusicAlbum",
|
||||
itemType: "MusicAlbum" as const,
|
||||
title: "Albums",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search albums...",
|
||||
@@ -599,7 +599,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
|
||||
it("should support tracklist display component", () => {
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -619,7 +619,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
describe("Config Simplification", () => {
|
||||
it("should not require searchFields in config", () => {
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
@@ -639,7 +639,7 @@ describe.skip("GenericMediaListPage", () => {
|
||||
|
||||
it("should not require compareFn in sort options", () => {
|
||||
const config = {
|
||||
itemType: "Audio",
|
||||
itemType: "Audio" as const,
|
||||
title: "Tracks",
|
||||
backPath: "/library/music",
|
||||
searchPlaceholder: "Search tracks...",
|
||||
|
||||
@@ -115,9 +115,11 @@
|
||||
<!-- Download indicator -->
|
||||
{#if showDownloadStatus && (isDownloaded || isDownloading)}
|
||||
{#if isDownloaded}
|
||||
<svg class="w-4 h-4 text-green-500 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" title="Downloaded">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v12m0 0l-4-4m4 4l4-4" />
|
||||
</svg>
|
||||
<span title="Downloaded">
|
||||
<svg class="w-4 h-4 text-green-500 flex-shrink-0" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" aria-label="Downloaded">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M12 4v12m0 0l-4-4m4 4l4-4" />
|
||||
</svg>
|
||||
</span>
|
||||
{:else if isDownloading}
|
||||
<div class="w-4 h-4 relative flex-shrink-0" title="Downloading...">
|
||||
<svg class="w-4 h-4 -rotate-90" viewBox="0 0 24 24">
|
||||
|
||||
@@ -35,7 +35,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
@@ -67,7 +68,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
@@ -100,7 +102,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem1 = {
|
||||
id: "item1",
|
||||
name: "Album 1",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "tag1",
|
||||
};
|
||||
|
||||
@@ -118,7 +121,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem2 = {
|
||||
id: "item2",
|
||||
name: "Album 2",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "tag2",
|
||||
};
|
||||
|
||||
@@ -136,7 +140,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
@@ -159,7 +164,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
// primaryImageTag is undefined
|
||||
};
|
||||
|
||||
@@ -182,7 +188,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
@@ -206,7 +213,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
@@ -231,7 +239,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "tag123",
|
||||
};
|
||||
|
||||
@@ -259,7 +268,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
@@ -292,14 +302,16 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const item1 = {
|
||||
id: "item1",
|
||||
name: "Album 1",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "tag1",
|
||||
};
|
||||
|
||||
const item2 = {
|
||||
id: "item2",
|
||||
name: "Album 2",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "tag2",
|
||||
};
|
||||
|
||||
@@ -331,7 +343,8 @@ describe.skip("MediaCard - Async Image Loading", () => {
|
||||
const mediaItem = {
|
||||
id: "item123",
|
||||
name: "Test Album",
|
||||
type: "MusicAlbum",
|
||||
type: "MusicAlbum" as const,
|
||||
serverId: "server-1",
|
||||
primaryImageTag: "abc123",
|
||||
};
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
<!-- TRACES: UR-036 | JA-030, JA-031 | DR-041 -->
|
||||
<script lang="ts">
|
||||
import type { MediaItem } from "$lib/api/types";
|
||||
import type { MediaItem, Library } from "$lib/api/types";
|
||||
import { auth } from "$lib/stores/auth";
|
||||
import { onMount } from "svelte";
|
||||
import LibraryGrid from "./LibraryGrid.svelte";
|
||||
@@ -39,7 +40,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
function handleItemClick(item: MediaItem) {
|
||||
function handleItemClick(item: MediaItem | Library) {
|
||||
goto(`/library/${item.id}`);
|
||||
}
|
||||
</script>
|
||||
|
||||
@@ -322,16 +322,10 @@ describe("TrackList Logic Tests", () => {
|
||||
it("should invoke player when no custom callback", async () => {
|
||||
const invokeMock = (invoke as any).mockResolvedValue(undefined);
|
||||
|
||||
// Simulate unified handler without custom callback
|
||||
const onTrackClick = undefined;
|
||||
if (onTrackClick) {
|
||||
await onTrackClick(mockTracks[0], 0);
|
||||
} else {
|
||||
// This branch executes - default handler
|
||||
await invoke("player_play_queue", {
|
||||
request: { items: [], startIndex: 0, shuffle: false },
|
||||
});
|
||||
}
|
||||
// Simulate unified handler without custom callback - default handler runs
|
||||
await invoke("player_play_queue", {
|
||||
request: { items: [], startIndex: 0, shuffle: false },
|
||||
});
|
||||
|
||||
expect(invokeMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@@ -332,8 +332,6 @@ describe.skip("TrackList", () => {
|
||||
// NOTE: This test is skipped because stream URLs are no longer fetched by frontend.
|
||||
// The code now uses player_play_tracks which sends trackIds to backend.
|
||||
// Backend handles all stream URL generation, so this error path no longer exists.
|
||||
|
||||
alertSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user