Adds the /app/decos screen (dual-mode list/editor) mirroring the legacy Blazor deco form: deco/watermark/graphics/break-content/default-filler/dead-air sections with mode-gated controls, watermark/graphics multi-selects, break content with a playlist group->playlist cascade and per-placement uniqueness, and default-filler/dead-air typeahead pickers. Adds decos/playlists api modules, artist/multi-collection search wrappers, and regenerated types. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
105 lines
3.9 KiB
TypeScript
105 lines
3.9 KiB
TypeScript
import { ApiError, request } from './client';
|
|
import type { components } from './generated/v1';
|
|
|
|
export type BlockGroup = components['schemas']['BlockGroupResponseModel'];
|
|
export type Block = components['schemas']['BlockResponseModel'];
|
|
export type BlockItem = components['schemas']['BlockItemResponseModel'];
|
|
export type BlockWithItems = components['schemas']['BlockWithItemsResponseModel'];
|
|
export type BlockPreviewItem = components['schemas']['BlockPreviewItemResponseModel'];
|
|
export type CreateBlockGroupRequest = components['schemas']['CreateBlockGroupRequest'];
|
|
export type CreateBlockRequest = components['schemas']['CreateBlockRequest'];
|
|
export type ReplaceBlockRequest = components['schemas']['ReplaceBlockRequest'];
|
|
export type BlockItemRequest = components['schemas']['BlockItemRequest'];
|
|
export type CopyBlockRequest = components['schemas']['CopyBlockRequest'];
|
|
export type SchedulingPickerOption = components['schemas']['SchedulingPickerOptionResponseModel'];
|
|
|
|
// Block groups
|
|
|
|
export function getBlockGroups(): Promise<BlockGroup[]> {
|
|
return request<BlockGroup[]>('/api/blocks/groups');
|
|
}
|
|
|
|
export function createBlockGroup(body: CreateBlockGroupRequest): Promise<BlockGroup> {
|
|
return request<BlockGroup>('/api/blocks/groups', { body, method: 'POST' });
|
|
}
|
|
|
|
export function deleteBlockGroup(id: number): Promise<void> {
|
|
return request<void>(`/api/blocks/groups/${id}`, { method: 'DELETE' });
|
|
}
|
|
|
|
// Blocks
|
|
|
|
export function getBlocks(): Promise<Block[]> {
|
|
return request<Block[]>('/api/blocks');
|
|
}
|
|
|
|
export function getBlock(id: number): Promise<Block> {
|
|
return request<Block>(`/api/blocks/${id}`);
|
|
}
|
|
|
|
export function createBlock(body: CreateBlockRequest): Promise<Block> {
|
|
return request<Block>('/api/blocks', { body, method: 'POST' });
|
|
}
|
|
|
|
export function deleteBlock(id: number): Promise<void> {
|
|
return request<void>(`/api/blocks/${id}`, { method: 'DELETE' });
|
|
}
|
|
|
|
export function getBlockItems(id: number): Promise<BlockItem[]> {
|
|
return request<BlockItem[]>(`/api/blocks/${id}/items`);
|
|
}
|
|
|
|
export function replaceBlock(id: number, body: ReplaceBlockRequest): Promise<BlockWithItems> {
|
|
return request<BlockWithItems>(`/api/blocks/${id}`, { body, method: 'PUT' });
|
|
}
|
|
|
|
export function previewBlock(id: number, body: ReplaceBlockRequest): Promise<BlockPreviewItem[]> {
|
|
return request<BlockPreviewItem[]>(`/api/blocks/${id}/preview`, { body, method: 'POST' });
|
|
}
|
|
|
|
export function copyBlock(id: number, body: CopyBlockRequest): Promise<Block> {
|
|
return request<Block>(`/api/blocks/${id}/copy`, { body, method: 'POST' });
|
|
}
|
|
|
|
// Scheduling search pickers
|
|
|
|
function searchOptions(path: string, query: string): Promise<SchedulingPickerOption[]> {
|
|
return request<SchedulingPickerOption[]>(`${path}?query=${encodeURIComponent(query)}`);
|
|
}
|
|
|
|
export function searchCollections(query: string): Promise<SchedulingPickerOption[]> {
|
|
return searchOptions('/api/search/collections', query);
|
|
}
|
|
|
|
export function searchTelevisionShows(query: string): Promise<SchedulingPickerOption[]> {
|
|
return searchOptions('/api/search/television-shows', query);
|
|
}
|
|
|
|
export function searchTelevisionSeasons(query: string): Promise<SchedulingPickerOption[]> {
|
|
return searchOptions('/api/search/television-seasons', query);
|
|
}
|
|
|
|
export function searchSmartCollections(query: string): Promise<SchedulingPickerOption[]> {
|
|
return searchOptions('/api/search/smart-collections', query);
|
|
}
|
|
|
|
export function searchArtists(query: string): Promise<SchedulingPickerOption[]> {
|
|
return searchOptions('/api/search/artists', query);
|
|
}
|
|
|
|
export function searchMultiCollections(query: string): Promise<SchedulingPickerOption[]> {
|
|
return searchOptions('/api/search/multi-collections', query);
|
|
}
|
|
|
|
export function messageFromBlockError(error: unknown, fallback = 'Unable to load blocks'): string {
|
|
if (error instanceof ApiError) {
|
|
return error.detail ?? error.message;
|
|
}
|
|
|
|
if (error instanceof Error) {
|
|
return error.message;
|
|
}
|
|
|
|
return fallback;
|
|
}
|