Files
hertzbeat/web-next/lib/entity-import/controller.ts
T
Logic 2de48d2caa feat: complete HertzBeat 2.0 novice workflows
Refine entity, monitor, alert, settings, observability, and shared operator workflows; add scale guards, route compatibility, release validation, and Product Design coverage.

AI assistance: used for draft implementation and test iteration.\nHuman validation: Node 22 production build; 426 frontend files and 3,398 tests; 59-route matrix; release budget 7.84 MiB / 8.00 MiB; focused backend tests and Browser QA.\nRisk notes: local scale proof covers 2,005 entities; sustained concurrent-ingestion SLA remains deployment-specific.
2026-07-10 14:54:43 +08:00

99 lines
3.0 KiB
TypeScript

import type {
EntityDefinitionActivity,
EntityDefinitionFormat,
EntityDefinitionRequest,
EntityDefinitionWorkspaceTemplate,
EntityDto
} from '@/lib/types';
type ApiGetter = <T>(url: string) => Promise<T>;
type ApiPoster = <T>(url: string, body: EntityDefinitionRequest) => Promise<T>;
type EntityImportReaders = {
templates: (limit?: number) => Promise<EntityDefinitionWorkspaceTemplate[]>;
activities: (limit?: number) => Promise<EntityDefinitionActivity[]>;
};
export function buildImportTemplatesUrl(limit = 8) {
const params = new URLSearchParams({ limit: String(limit) });
return `/entities/definition/templates?${params.toString()}`;
}
export function buildImportActivitiesUrl(limit = 8) {
const params = new URLSearchParams({ limit: String(limit) });
return `/entities/definition-activities?${params.toString()}`;
}
function isRecoverableImportLoadError(error: unknown) {
if (!(error instanceof Error)) {
return false;
}
return error.message.includes('404')
|| error.message.includes('ECONNRESET')
|| error.message.includes('socket hang up')
|| error.message.includes('Backend service unavailable.')
|| error.message.includes('API request failed: 503');
}
async function loadImportTemplates(apiGet: ApiGetter) {
try {
return await apiGet<EntityDefinitionWorkspaceTemplate[]>(buildImportTemplatesUrl());
} catch (error) {
if (isRecoverableImportLoadError(error)) {
return [];
}
throw error;
}
}
async function loadImportActivities(apiGet: ApiGetter) {
try {
return await apiGet<EntityDefinitionActivity[]>(buildImportActivitiesUrl());
} catch (error) {
if (isRecoverableImportLoadError(error)) {
return [];
}
throw error;
}
}
export async function loadImportData(apiGet: ApiGetter) {
const [templates, activities] = await Promise.all([
loadImportTemplates(apiGet),
loadImportActivities(apiGet)
]);
return { templates, activities };
}
export async function loadImportDataFromFacade(readers: EntityImportReaders) {
const [templates, activities] = await Promise.all([
readers.templates(8).catch(error => {
if (isRecoverableImportLoadError(error)) {
return [];
}
throw error;
}),
readers.activities(8).catch(error => {
if (isRecoverableImportLoadError(error)) {
return [];
}
throw error;
})
]);
return { templates, activities };
}
export function buildDefinitionRequest(content: string, format: EntityDefinitionFormat): EntityDefinitionRequest {
return { content, format };
}
export async function parseDefinitionBundle(apiPost: ApiPoster, content: string, format: EntityDefinitionFormat) {
return apiPost<EntityDto[]>('/entities/definition/bundle/parse', buildDefinitionRequest(content, format));
}
export async function createDefinitionBundle(apiPost: ApiPoster, content: string, format: EntityDefinitionFormat) {
return apiPost<number[]>('/entities/definition/bundle', buildDefinitionRequest(content, format));
}