feat(web): tag enrichment sources admin card (#1490 Step 4 web)
Add a "Tag enrichment sources" card to the admin integrations page, mirroring the cover-art providers card: per-provider enable toggle + API-key field + Save + Test connection, over /api/admin/tag-sources. Enabling/keying a source (e.g. pasting a Last.fm key) re-opens settled tracks for re-enrichment via the version bump. - admin.ts: TagProvider types + get/update/test functions + createTagProvidersQuery; qk.tagProviders key. - integrations/+page.svelte: the card + local edit state, with MusicBrainz (keyless baseline) and Last.fm (needs a free key) notes. - Tests: admin.tag-sources API test + integrations component tests (render / enable+key save / test connection), plus the mock plumbing the existing suite needs for the new query. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -383,6 +383,67 @@ export function createCoverProvidersQuery() {
|
||||
});
|
||||
}
|
||||
|
||||
// Tag-enrichment providers -------------------------------------------------
|
||||
// Parallel to the cover-art providers surface, over /api/admin/tag-sources.
|
||||
// Independent settings so a new folksonomy source is added without touching
|
||||
// art config (#1490).
|
||||
|
||||
export type TagProviderCapability = 'track_tags';
|
||||
|
||||
export type TagProvider = {
|
||||
id: string;
|
||||
display_name: string;
|
||||
requires_api_key: boolean;
|
||||
supports: TagProviderCapability[];
|
||||
enabled: boolean;
|
||||
api_key_set: boolean;
|
||||
display_order: number;
|
||||
testable: boolean;
|
||||
};
|
||||
|
||||
export type TagProvidersResponse = {
|
||||
providers: TagProvider[];
|
||||
sources_version: number;
|
||||
};
|
||||
|
||||
export async function getTagProviders(): Promise<TagProvidersResponse> {
|
||||
return api.get<TagProvidersResponse>('/api/admin/tag-sources');
|
||||
}
|
||||
|
||||
export type UpdateTagProviderPatch = {
|
||||
enabled?: boolean;
|
||||
api_key?: string;
|
||||
};
|
||||
|
||||
export type UpdateTagProviderResponse = TagProvider & {
|
||||
version_bumped: boolean;
|
||||
};
|
||||
|
||||
export async function updateTagProvider(
|
||||
id: string,
|
||||
patch: UpdateTagProviderPatch
|
||||
): Promise<UpdateTagProviderResponse> {
|
||||
return api.patch<UpdateTagProviderResponse>(`/api/admin/tag-sources/${id}`, patch);
|
||||
}
|
||||
|
||||
export type TestTagProviderResponse = {
|
||||
ok: boolean;
|
||||
duration_ms?: number;
|
||||
error?: string;
|
||||
};
|
||||
|
||||
export async function testTagProvider(id: string): Promise<TestTagProviderResponse> {
|
||||
return api.post<TestTagProviderResponse>(`/api/admin/tag-sources/${id}/test`, {});
|
||||
}
|
||||
|
||||
export function createTagProvidersQuery() {
|
||||
return createQuery({
|
||||
queryKey: qk.tagProviders(),
|
||||
queryFn: getTagProviders,
|
||||
staleTime: 60_000
|
||||
});
|
||||
}
|
||||
|
||||
// Admin user-management ------------------------------------------------------
|
||||
|
||||
export type AdminUser = {
|
||||
|
||||
Reference in New Issue
Block a user