Files
ss-tools/frontend/src/lib/api/reports.js
2026-02-26 19:40:00 +03:00

107 lines
4.1 KiB
JavaScript

// [DEF:frontend.src.lib.api.reports:Module]
// @TIER: CRITICAL
// @SEMANTICS: frontend, api_client, reports, wrapper
// @PURPOSE: Wrapper-based reports API client for list/detail retrieval without direct native fetch usage.
// @LAYER: Infra
// @RELATION: DEPENDS_ON -> [DEF:api_module]
// @INVARIANT: Uses existing api wrapper methods and returns structured errors for UI-state mapping.
import { api } from '../api.js';
// [DEF:buildReportQueryString:Function]
// @PURPOSE: Build query string for reports list endpoint from filter options.
// @PRE: options is an object with optional report query fields.
// @POST: Returns URL query string without leading '?'.
export function buildReportQueryString(options = {}) {
console.log("[reports][api][buildReportQueryString:START]");
const params = new URLSearchParams();
if (options.page != null) params.append('page', String(options.page));
if (options.page_size != null) params.append('page_size', String(options.page_size));
if (Array.isArray(options.task_types) && options.task_types.length > 0) {
params.append('task_types', options.task_types.join(','));
}
if (Array.isArray(options.statuses) && options.statuses.length > 0) {
params.append('statuses', options.statuses.join(','));
}
if (options.time_from) params.append('time_from', options.time_from);
if (options.time_to) params.append('time_to', options.time_to);
if (options.search) params.append('search', options.search);
if (options.sort_by) params.append('sort_by', options.sort_by);
if (options.sort_order) params.append('sort_order', options.sort_order);
return params.toString();
}
// [/DEF:buildReportQueryString:Function]
// [DEF:normalizeApiError:Function]
// @PURPOSE: Convert unknown API exceptions into deterministic UI-consumable error objects.
// @PRE: error may be Error/string/object.
// @POST: Returns structured error object.
export function normalizeApiError(error) {
console.log("[reports][api][normalizeApiError:START]");
const message =
(error && typeof error.message === 'string' && error.message) ||
(typeof error === 'string' && error) ||
'Failed to load reports';
return {
message,
code: 'REPORTS_API_ERROR',
retryable: true
};
}
// [/DEF:normalizeApiError:Function]
// [DEF:getReports:Function]
// @PURPOSE: Fetch unified report list using existing request wrapper.
// @PRE: valid auth context for protected endpoint.
// @POST: Returns parsed payload or structured error for UI-state mapping.
//
// @TEST_CONTRACT: GetReportsApi ->
// {
// required_fields: {},
// optional_fields: {options: Object},
// invariants: [
// "Fetches from /reports with built query string",
// "Returns response payload on success",
// "Catches and normalizes errors using normalizeApiError"
// ]
// }
// @TEST_FIXTURE: valid_get_reports -> {"options": {"page": 1}}
// @TEST_EDGE: api_fetch_failure -> api.fetchApi throws error
// @TEST_INVARIANT: error_normalization -> verifies: [api_fetch_failure]
export async function getReports(options = {}) {
try {
console.log("[reports][api][getReports:STARTED]", options);
const query = buildReportQueryString(options);
const res = await api.fetchApi(`/reports${query ? `?${query}` : ''}`);
console.log("[reports][api][getReports:SUCCESS]", res);
return res;
} catch (error) {
console.error("[reports][api][getReports:FAILED]", error);
throw normalizeApiError(error);
}
}
// [/DEF:getReports:Function]
// [DEF:getReportDetail:Function]
// @PURPOSE: Fetch one report detail by report_id.
// @PRE: reportId is non-empty string; valid auth context.
// @POST: Returns parsed detail payload or structured error object.
export async function getReportDetail(reportId) {
try {
console.log(`[reports][api][getReportDetail:STARTED] id=${reportId}`);
const res = await api.fetchApi(`/reports/${reportId}`);
console.log(`[reports][api][getReportDetail:SUCCESS] id=${reportId}`);
return res;
} catch (error) {
console.error(`[reports][api][getReportDetail:FAILED] id=${reportId}`, error);
throw normalizeApiError(error);
}
}
// [/DEF:getReportDetail:Function]
// [/DEF:frontend.src.lib.api.reports:Module]