mirror of
https://github.com/dromara/hertzbeat.git
synced 2026-10-02 14:09:07 +00:00
385 lines
9.2 KiB
JavaScript
385 lines
9.2 KiB
JavaScript
function toUrl(targetUrl) {
|
|
return targetUrl instanceof URL ? targetUrl : new URL(targetUrl, 'http://127.0.0.1');
|
|
}
|
|
|
|
function normalizeStubPath(targetUrl) {
|
|
const pathname = toUrl(targetUrl).pathname;
|
|
if (pathname === '/api') {
|
|
return '/';
|
|
}
|
|
return pathname.startsWith('/api/') ? pathname.slice(4) : pathname;
|
|
}
|
|
|
|
function readIntegerParam(targetUrl, key, fallbackValue) {
|
|
const raw = toUrl(targetUrl).searchParams.get(key);
|
|
if (raw == null) {
|
|
return fallbackValue;
|
|
}
|
|
|
|
const parsed = Number.parseInt(raw, 10);
|
|
return Number.isFinite(parsed) ? parsed : fallbackValue;
|
|
}
|
|
|
|
function buildEmptyPage(targetUrl, defaultPageSize) {
|
|
const pageIndex = readIntegerParam(targetUrl, 'pageIndex', 0);
|
|
const pageSize = readIntegerParam(targetUrl, 'pageSize', defaultPageSize);
|
|
|
|
return {
|
|
content: [],
|
|
totalPages: 0,
|
|
totalElements: 0,
|
|
size: pageSize,
|
|
number: pageIndex,
|
|
numberOfElements: 0,
|
|
pageIndex,
|
|
pageSize
|
|
};
|
|
}
|
|
|
|
function buildStubEntityDto(targetUrl) {
|
|
const pathname = normalizeStubPath(targetUrl);
|
|
const rawId = pathname.split('/')[2] || '1';
|
|
const parsedId = Number.parseInt(rawId, 10);
|
|
const normalizedId = Number.isFinite(parsedId) ? parsedId : 1;
|
|
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
entity: {
|
|
id: normalizedId,
|
|
type: 'service',
|
|
name: `entity-${normalizedId}`,
|
|
displayName: `Entity ${normalizedId}`,
|
|
owner: 'platform',
|
|
system: 'catalog',
|
|
environment: 'prod',
|
|
lifecycle: 'production',
|
|
source: 'manual',
|
|
labels: {},
|
|
tags: [],
|
|
additionalOwners: [],
|
|
links: [],
|
|
contacts: [],
|
|
componentOf: [],
|
|
components: [],
|
|
implementedBy: [],
|
|
languages: []
|
|
},
|
|
identities: [],
|
|
monitorBinds: [],
|
|
relations: []
|
|
}
|
|
};
|
|
}
|
|
|
|
function buildStubEntityDefinition(targetUrl) {
|
|
const url = toUrl(targetUrl);
|
|
const rawId = normalizeStubPath(url).split('/')[2] || '1';
|
|
const format = url.searchParams.get('format') || 'yaml';
|
|
|
|
if (format === 'json') {
|
|
return {
|
|
code: 0,
|
|
data: JSON.stringify(
|
|
{
|
|
apiVersion: 'hertzbeat.apache.org/v1',
|
|
kind: 'Entity',
|
|
metadata: {
|
|
name: `entity-${rawId}`
|
|
},
|
|
spec: {
|
|
type: 'service',
|
|
displayName: `Entity ${rawId}`,
|
|
owner: 'platform',
|
|
system: 'catalog',
|
|
environment: 'prod',
|
|
source: 'manual'
|
|
}
|
|
},
|
|
null,
|
|
2
|
|
)
|
|
};
|
|
}
|
|
|
|
return {
|
|
code: 0,
|
|
data: [
|
|
'apiVersion: hertzbeat.apache.org/v1',
|
|
'kind: Entity',
|
|
'metadata:',
|
|
` name: entity-${rawId}`,
|
|
'spec:',
|
|
' type: service',
|
|
` displayName: Entity ${rawId}`,
|
|
' owner: platform',
|
|
' system: catalog',
|
|
' environment: prod',
|
|
' source: manual'
|
|
].join('\n')
|
|
};
|
|
}
|
|
|
|
function buildStubEntityDetail(targetUrl) {
|
|
const rawId = normalizeStubPath(targetUrl).split('/')[2] || '1';
|
|
const parsedId = Number.parseInt(rawId, 10);
|
|
const normalizedId = Number.isFinite(parsedId) ? parsedId : 1;
|
|
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
entity: {
|
|
entity: {
|
|
id: normalizedId,
|
|
name: `entity-${normalizedId}`,
|
|
displayName: `Entity ${normalizedId}`,
|
|
type: 'service',
|
|
status: 'unknown',
|
|
owner: 'platform',
|
|
environment: 'prod',
|
|
system: 'catalog',
|
|
source: 'manual',
|
|
description: 'Fallback entity workspace while backend entity detail APIs are unavailable.'
|
|
},
|
|
identities: [],
|
|
monitorBinds: [],
|
|
relations: []
|
|
},
|
|
evidenceSummary: {
|
|
activeAlertCount: 0,
|
|
downMonitorCount: 0,
|
|
healthyMonitorCount: 0,
|
|
identityCount: 0,
|
|
logHintCount: 0,
|
|
lastEvidenceAt: null
|
|
},
|
|
alertSummary: {
|
|
totalActiveAlerts: 0,
|
|
latestStatusChangeAt: null
|
|
},
|
|
monitorSummary: {
|
|
totalBoundMonitors: 0,
|
|
latestStatusChangeAt: null
|
|
},
|
|
logSummary: {
|
|
hintCount: 0,
|
|
preferredQueryTitle: null,
|
|
fallbackSearchTerm: null
|
|
},
|
|
traceSummary: {
|
|
recentTraceCount: 0,
|
|
recentErrorTraceCount: 0,
|
|
latestObservedAt: null,
|
|
active: false,
|
|
latestTraceId: null
|
|
},
|
|
boundMonitors: [],
|
|
activeAlerts: [],
|
|
nextActions: [
|
|
{
|
|
actionType: 'definition',
|
|
title: 'Open definition workspace',
|
|
summary: 'Review the definition shell before adding ownership or evidence.',
|
|
actionLabel: 'Open definition',
|
|
priority: 1
|
|
}
|
|
]
|
|
}
|
|
};
|
|
}
|
|
|
|
export function buildAngularReferenceStubPayload(targetUrl) {
|
|
const normalizedPath = normalizeStubPath(targetUrl);
|
|
|
|
if (/^\/entities\/\d+$/.test(normalizedPath)) {
|
|
return buildStubEntityDto(targetUrl);
|
|
}
|
|
|
|
if (/^\/entities\/\d+\/detail$/.test(normalizedPath)) {
|
|
return buildStubEntityDetail(targetUrl);
|
|
}
|
|
|
|
if (/^\/entities\/\d+\/alerts$/.test(normalizedPath) || /^\/entities\/\d+\/monitors$/.test(normalizedPath)) {
|
|
return {
|
|
code: 0,
|
|
data: buildEmptyPage(targetUrl, 10)
|
|
};
|
|
}
|
|
|
|
if (/^\/entities\/\d+\/definition$/.test(normalizedPath)) {
|
|
return buildStubEntityDefinition(targetUrl);
|
|
}
|
|
|
|
switch (normalizedPath) {
|
|
case '/apps/hierarchy':
|
|
return {
|
|
code: 0,
|
|
data: []
|
|
};
|
|
case '/config/mute':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
mute: true
|
|
}
|
|
};
|
|
case '/alerts':
|
|
case '/monitors':
|
|
return {
|
|
code: 0,
|
|
data: buildEmptyPage(targetUrl, 10)
|
|
};
|
|
case '/entities':
|
|
return {
|
|
code: 0,
|
|
data: buildEmptyPage(targetUrl, 10)
|
|
};
|
|
case '/entities/definition-activities':
|
|
case '/entities/definition/templates':
|
|
case '/entities/discovery/governance-presets':
|
|
case '/entities/discovery/governance-activities':
|
|
case '/entities/definition/workspace-activities':
|
|
return {
|
|
code: 0,
|
|
data: []
|
|
};
|
|
case '/entities/catalog-suggestions':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
owners: [],
|
|
namespaces: [],
|
|
environments: [],
|
|
systems: [],
|
|
lifecycles: [],
|
|
tiers: [],
|
|
inheritFromRefs: [],
|
|
entityRefs: [],
|
|
languages: [],
|
|
linkProviders: []
|
|
}
|
|
};
|
|
case '/ingestion/otlp/overview':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
metrics: {
|
|
signal: 'metrics',
|
|
active: false,
|
|
totalCount: 0,
|
|
latestObservedAt: null,
|
|
intakeMode: 'pull',
|
|
summary: ''
|
|
},
|
|
logs: {
|
|
signal: 'logs',
|
|
active: false,
|
|
totalCount: 0,
|
|
latestObservedAt: null,
|
|
intakeMode: 'push',
|
|
summary: ''
|
|
},
|
|
traces: {
|
|
signal: 'traces',
|
|
active: false,
|
|
totalCount: 0,
|
|
latestObservedAt: null,
|
|
intakeMode: 'push',
|
|
summary: ''
|
|
},
|
|
activeSignalCount: 0,
|
|
latestObservedAt: null,
|
|
recentServiceCount: 0,
|
|
boundEntityCount: 0,
|
|
recentEvents: []
|
|
}
|
|
};
|
|
case '/ingestion/otlp/guide':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
httpProtocolLabel: 'HTTP',
|
|
grpcProtocolLabel: 'gRPC',
|
|
authHeaderName: 'Authorization',
|
|
authHeaderExample: 'Bearer <token>',
|
|
grpcAuthorityExample: '',
|
|
signals: [],
|
|
snippets: []
|
|
}
|
|
};
|
|
case '/ingestion/otlp/bindings':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
canonicalIdentityKeys: [],
|
|
recentServices: [],
|
|
recentIdentitySamples: [],
|
|
recentBoundEntities: []
|
|
}
|
|
};
|
|
case '/ingestion/otlp/metrics/console':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
context: {},
|
|
query: null,
|
|
datasource: null,
|
|
queryMode: null,
|
|
results: {
|
|
refId: null,
|
|
status: 0,
|
|
msg: '',
|
|
frames: []
|
|
},
|
|
stats: {
|
|
totalSeries: 0,
|
|
nonEmptySeries: 0,
|
|
latestObservedAt: null
|
|
},
|
|
emptyStateReason: 'no-data',
|
|
errorMessage: null
|
|
}
|
|
};
|
|
case '/traces/list':
|
|
return {
|
|
code: 0,
|
|
data: buildEmptyPage(targetUrl, 20)
|
|
};
|
|
case '/traces/stats/overview':
|
|
return {
|
|
code: 0,
|
|
data: {
|
|
totalTraceCount: 0,
|
|
errorTraceCount: 0,
|
|
latestObservedAt: null,
|
|
hasActiveTrace: false
|
|
}
|
|
};
|
|
default:
|
|
return null;
|
|
}
|
|
}
|
|
|
|
export function resolveAngularReferenceStubResponse({ method = 'GET', targetUrl, upstreamStatus }) {
|
|
if (upstreamStatus !== 404) {
|
|
return null;
|
|
}
|
|
|
|
if (method !== 'GET' && method !== 'HEAD') {
|
|
return null;
|
|
}
|
|
|
|
const payload = buildAngularReferenceStubPayload(targetUrl);
|
|
if (!payload) {
|
|
return null;
|
|
}
|
|
|
|
return {
|
|
status: 200,
|
|
headers: {
|
|
'Content-Type': 'application/json; charset=utf-8'
|
|
},
|
|
body: method === 'HEAD' ? '' : JSON.stringify(payload)
|
|
};
|
|
}
|