fix(web): 補 Work Items 租戶讀取上下文
This commit is contained in:
@@ -1105,6 +1105,11 @@ async function fetchJson<T>(url: string, timeoutMs = 8000): Promise<T | null> {
|
||||
}
|
||||
}
|
||||
|
||||
function withProjectId(url: string, projectId: string) {
|
||||
const separator = url.includes("?") ? "&" : "?";
|
||||
return `${url}${separator}project_id=${encodeURIComponent(projectId)}`;
|
||||
}
|
||||
|
||||
async function postJson<T>(
|
||||
url: string,
|
||||
body: Record<string, unknown>,
|
||||
@@ -1146,8 +1151,14 @@ function recurrenceOpenItems(recurrence: RecurrenceResponse | null) {
|
||||
return (recurrence?.items ?? []).filter((item) => item.work_item?.status === "open");
|
||||
}
|
||||
|
||||
const CANONICAL_INCIDENT_ID_RE = /^INC-\d{8}-[A-Z0-9]{4,}$/;
|
||||
|
||||
function isCanonicalIncidentId(candidate: string | null | undefined) {
|
||||
return Boolean(candidate?.trim() && CANONICAL_INCIDENT_ID_RE.test(candidate.trim()));
|
||||
}
|
||||
|
||||
function firstIncidentId(...candidates: Array<string | null | undefined>) {
|
||||
return candidates.find((candidate) => Boolean(candidate?.trim()))?.trim() ?? null;
|
||||
return candidates.find(isCanonicalIncidentId)?.trim() ?? null;
|
||||
}
|
||||
|
||||
function parseRepairCandidateDraftWorkItemId(
|
||||
@@ -6105,22 +6116,46 @@ export default function AwoooPWorkItemsPage() {
|
||||
setLoading(true);
|
||||
const encodedProjectId = encodeURIComponent(projectId);
|
||||
const qualityUrl = `${API_BASE}/api/v1/platform/truth-chain/quality/summary?project_id=${encodedProjectId}&hours=24&limit=30`;
|
||||
const governanceEventsUrl = `${API_BASE}/api/v1/ai/governance/events?event_type=knowledge_degradation&event_type=governance_slo_data_gap&status=unresolved&size=10`;
|
||||
const governanceQueueUrl = `${API_BASE}/api/v1/ai/governance/queue?dispatch_status=pending&size=10`;
|
||||
const governanceKnowledgeQueueUrl = `${API_BASE}/api/v1/ai/governance/queue?dispatch_status=all&event_type=knowledge_degradation&size=20`;
|
||||
const knowledgeReviewDraftsUrl = `${API_BASE}/api/v1/knowledge?entry_type=auto_runbook&status=review&q=${encodeURIComponent("KM healthcheck")}&limit=100`;
|
||||
const knowledgeReviewDedupeUrl = `${API_BASE}/api/v1/ai/governance/km-review-drafts/dedupe?limit=100`;
|
||||
const governanceEventsUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/ai/governance/events?event_type=knowledge_degradation&event_type=governance_slo_data_gap&status=unresolved&size=10`,
|
||||
projectId
|
||||
);
|
||||
const governanceQueueUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/ai/governance/queue?dispatch_status=pending&size=10`,
|
||||
projectId
|
||||
);
|
||||
const governanceKnowledgeQueueUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/ai/governance/queue?dispatch_status=all&event_type=knowledge_degradation&size=20`,
|
||||
projectId
|
||||
);
|
||||
const knowledgeReviewDraftsUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/knowledge?entry_type=auto_runbook&status=review&q=${encodeURIComponent("KM healthcheck")}&limit=100`,
|
||||
projectId
|
||||
);
|
||||
const knowledgeReviewDedupeUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/ai/governance/km-review-drafts/dedupe?limit=100`,
|
||||
projectId
|
||||
);
|
||||
const knowledgeStaleCandidatesUrl = `${API_BASE}/api/v1/ai/governance/km-stale-candidates?project_id=${encodedProjectId}&limit=20`;
|
||||
const knowledgeStaleOwnerReviewsUrl = `${API_BASE}/api/v1/ai/governance/km-stale-owner-reviews?project_id=${encodedProjectId}&dispatch_status=pending&limit=30`;
|
||||
const knowledgeStaleOwnerReviewBurnDownUrl = `${API_BASE}/api/v1/ai/governance/km-stale-owner-review-burndown?project_id=${encodedProjectId}&limit=20`;
|
||||
const knowledgeStaleOwnerReviewCompletionQueueUrl = `${API_BASE}/api/v1/ai/governance/km-stale-owner-review-completion-queue?project_id=${encodedProjectId}&status_bucket=all&limit=30`;
|
||||
const channelEventsUrl = `${API_BASE}/api/v1/platform/events/recent?project_id=${encodedProjectId}&provider_prefix=alertmanager&limit=20`;
|
||||
const recurrenceUrl = `${API_BASE}/api/v1/platform/events/dossier/recurrence?project_id=${encodedProjectId}&limit=100`;
|
||||
const sloUrl = `${API_BASE}/api/v1/ai/slo`;
|
||||
const remediationHistoryUrl = `${API_BASE}/api/v1/ai/slo/remediation/history?limit=80`;
|
||||
const driftFingerprintUrl = `${API_BASE}/api/v1/drift/fingerprints/state?namespace=awoooi-prod`;
|
||||
const sloUrl = withProjectId(`${API_BASE}/api/v1/ai/slo`, projectId);
|
||||
const remediationHistoryUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/ai/slo/remediation/history?limit=80`,
|
||||
projectId
|
||||
);
|
||||
const driftFingerprintUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/drift/fingerprints/state?namespace=awoooi-prod`,
|
||||
projectId
|
||||
);
|
||||
const callbackRepliesUrl = `${API_BASE}/api/v1/platform/runs/callback-replies?project_id=${encodedProjectId}&per_page=100`;
|
||||
const aiRouteStatusUrl = `${API_BASE}/api/v1/platform/ai-route-status?workload_type=deep_rca`;
|
||||
const aiRouteStatusUrl = withProjectId(
|
||||
`${API_BASE}/api/v1/platform/ai-route-status?workload_type=deep_rca`,
|
||||
projectId
|
||||
);
|
||||
|
||||
const [
|
||||
quality,
|
||||
@@ -6177,7 +6212,10 @@ export default function AwoooPWorkItemsPage() {
|
||||
const timelineIncidentId = statusChain?.source_id ?? statusChainIncidentId;
|
||||
const incidentTimeline = timelineIncidentId
|
||||
? await fetchJson<IncidentTimelineResponse>(
|
||||
`${API_BASE}/api/v1/incidents/${encodeURIComponent(timelineIncidentId)}/timeline`,
|
||||
withProjectId(
|
||||
`${API_BASE}/api/v1/incidents/${encodeURIComponent(timelineIncidentId)}/timeline`,
|
||||
projectId
|
||||
),
|
||||
12000
|
||||
)
|
||||
: null;
|
||||
|
||||
Reference in New Issue
Block a user