import { getApiBaseUrl } from "./api-base"; // Forgejo Connection types export interface ForgejoConnection { id: string; organization_id: string; name: string; base_url: string; token: null; // Always null in responses active: boolean; has_token: boolean; token_last_eight: string | null; created_at: string; updated_at: string; } export interface ForgejoConnectionCreate { name: string; base_url: string; token: string; } export interface ForgejoConnectionUpdate { name?: string; base_url?: string; token?: string; } // Forgejo Repository types export interface ForgejoRepository { id: string; organization_id: string; connection_id: string; owner: string; repo: string; display_name: string; default_branch: string; active: boolean; connection: ForgejoConnection; last_sync_at: string | null; last_sync_error: string | null; created_at: string; updated_at: string; } export interface ForgejoRepositoryCreate { connection_id: string; owner: string; repo: string; display_name?: string; default_branch?: string; } export interface ForgejoRepositoryUpdate { display_name?: string; default_branch?: string; } // API client const API_BASE_URL = getApiBaseUrl(); async function fetchJson(url: string, init?: RequestInit): Promise { const response = await fetch(url, { ...init, headers: { "Content-Type": "application/json", ...(init?.headers || {}), }, }); if (!response.ok) { const errorData = await response.json().catch(() => ({})); throw new Error(errorData.detail || `API error: ${response.statusText}`); } return response.json(); } // Forgejo Connection API export async function getForgejoConnections(): Promise { return fetchJson(`${API_BASE_URL}/api/v1/forgejo/connections`); } export async function createForgejoConnection( data: ForgejoConnectionCreate, ): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/connections`, { method: "POST", body: JSON.stringify(data), }, ); } export async function getForgejoConnection( connectionId: string, ): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/connections/${connectionId}`, ); } export async function updateForgejoConnection( connectionId: string, data: ForgejoConnectionUpdate, ): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/connections/${connectionId}`, { method: "PATCH", body: JSON.stringify(data), }, ); } export async function deleteForgejoConnection(connectionId: string): Promise { await fetch(`${API_BASE_URL}/api/v1/forgejo/connections/${connectionId}`, { method: "DELETE", }); } // Forgejo Repository API export async function getForgejoRepositories(): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/repositories`, ); } export async function createForgejoRepository( data: ForgejoRepositoryCreate, ): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/repositories`, { method: "POST", body: JSON.stringify(data), }, ); } export async function getForgejoRepository( repositoryId: string, ): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/repositories/${repositoryId}`, ); } export async function updateForgejoRepository( repositoryId: string, data: ForgejoRepositoryUpdate, ): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/repositories/${repositoryId}`, { method: "PATCH", body: JSON.stringify(data), }, ); } export async function deleteForgejoRepository(repositoryId: string): Promise { await fetch(`${API_BASE_URL}/api/v1/forgejo/repositories/${repositoryId}`, { method: "DELETE", }); } // Forgejo Sync & Validation API export async function syncRepository( repositoryId: string, ): Promise<{ created: number; updated: number; open: number; closed: number; total: number; }> { return fetchJson<{ created: number; updated: number; open: number; closed: number; total: number }>( `${API_BASE_URL}/api/v1/forgejo/repositories/${repositoryId}/sync`, { method: "POST", }, ); } export async function validateConnection( connectionId: string, ): Promise<{ ok: boolean; error_message?: string; response_time_ms: number; }> { return fetchJson<{ ok: boolean; error_message?: string; response_time_ms: number; }>( `${API_BASE_URL}/api/v1/forgejo/connections/${connectionId}/validate`, { method: "POST", }, ); } export async function validateRepository( repositoryId: string, ): Promise<{ ok: boolean; repo_exists: boolean; error_message?: string; }> { return fetchJson<{ ok: boolean; repo_exists: boolean; error_message?: string; }>( `${API_BASE_URL}/api/v1/forgejo/repositories/${repositoryId}/validate`, { method: "POST", }, ); } // Forgejo Issue types export interface ForgejoIssue { id: string; organization_id: string; repository_id: string; forgejo_issue_number: number; title: string; body_preview: string | null; state: string; is_pull_request: boolean; labels: Record[]; assignees: Record[]; author: string; html_url: string; forgejo_created_at: string; forgejo_updated_at: string; forgejo_closed_at: string | null; last_synced_at: string; created_at: string; updated_at: string; } export interface ForgejoIssueListResponse { items: ForgejoIssue[]; total: number; page: number; limit: number; } // Forgejo Issue API export async function getForgejoIssues(params?: { repository_id?: string; state?: string; search?: string; page?: number; limit?: number; }): Promise { const searchParams = new URLSearchParams(); if (params?.repository_id) searchParams.set("repository_id", params.repository_id); if (params?.state) searchParams.set("state", params.state); if (params?.search) searchParams.set("search", params.search); if (params?.page) searchParams.set("page", params.page.toString()); if (params?.limit) searchParams.set("limit", params.limit.toString()); const qs = searchParams.toString(); return fetchJson( `${API_BASE_URL}/api/v1/forgejo/issues${qs ? `?${qs}` : ""}`, ); } export async function getForgejoIssue(issueId: string): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/issues/${issueId}`, ); } export async function closeForgejoIssue(issueId: string): Promise { return fetchJson( `${API_BASE_URL}/api/v1/forgejo/issues/${issueId}/close`, { method: "POST", }, ); } // Board Repository Linking API export async function getBoardForgejoRepositories(boardId: string): Promise<{ repositories: Array<{ id: string; board_id: string; repository_id: string; organization_id: string; created_at: string; repository: ForgejoRepository; }>; }> { return fetchJson<{ repositories: Array<{ id: string; board_id: string; repository_id: string; organization_id: string; created_at: string; repository: ForgejoRepository; }>; }>( `${API_BASE_URL}/api/v1/boards/${boardId}/forgejo/repositories`, ); } export async function linkBoardForgejoRepository( boardId: string, repositoryId: string, ): Promise<{ id: string; board_id: string; repository_id: string; organization_id: string; created_at: string; repository: ForgejoRepository; }> { return fetchJson<{ id: string; board_id: string; repository_id: string; organization_id: string; created_at: string; repository: ForgejoRepository; }>( `${API_BASE_URL}/api/v1/boards/${boardId}/forgejo/repositories`, { method: "POST", body: JSON.stringify({ repository_id: repositoryId }), }, ); } export async function unlinkBoardForgejoRepository( boardId: string, repositoryId: string, ): Promise { await fetch( `${API_BASE_URL}/api/v1/boards/${boardId}/forgejo/repositories/${repositoryId}`, { method: "DELETE", }, ); } // Forgejo Metrics types export interface RepositorySyncHealth { repository_id: string; owner: string; repo: string; display_name: string | null; last_sync_at: string | null; last_sync_error: string | null; has_error: boolean; } export interface ForgejoIssueMetrics { open_issues: number; closed_issues: number; recently_closed: number; stale_open: number; total_issues: number; repositories_health: RepositorySyncHealth[]; } // Forgejo Metrics API export async function getForgejoMetrics(params?: { board_id?: string; repository_id?: string; }): Promise { const searchParams = new URLSearchParams(); if (params?.board_id) searchParams.set("board_id", params.board_id); if (params?.repository_id) searchParams.set("repository_id", params.repository_id); const qs = searchParams.toString(); return fetchJson( `${API_BASE_URL}/api/v1/forgejo/metrics${qs ? `?${qs}` : ""}`, ); }