@burdenoff/fluidgrids-fe-sdk 2026.1111.1 → 2026.1111.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{ExecutionDetailPage-DpAYZYx2.js → ExecutionDetailPage-Dpv1mVsb.js} +96 -34
- package/dist/{FailureTriagePanel-BJoO3lsL.js → FailureTriagePanel-D2RjCsYa.js} +97 -3
- package/dist/{FluidGridsProvider-CraUhM4E.js → FluidGridsProvider-Bg6wKnX4.js} +1 -1
- package/dist/{HistoryPage-CYqyngbp.js → HistoryPage-D75ICUi7.js} +3 -3
- package/dist/{InsightsPage-DBnOta71.js → InsightsPage-DFJ--w4r.js} +352 -72
- package/dist/{ManagedAiPolicyAuthority-D3AYZ5FP.js → ManagedAiPolicyAuthority-DsW8Jmm7.js} +297 -71
- package/dist/{MissingNodesInstallModal-LdB_-hSf.js → MissingNodesInstallModal-SlsOhIEf.js} +2 -2
- package/dist/{NodesPage-fEUyUKLC.js → NodesPage-CcHVwFdc.js} +2 -2
- package/dist/{PublishCustomNodeAction-C6qkAIjG.js → PublishCustomNodeAction-BzYU-juH.js} +1 -1
- package/dist/{TemplateConfigurationModal-CnqJFt2f.js → TemplateConfigurationModal-CdaNA1-J.js} +2 -2
- package/dist/{TemplateDetailPanel-BWnLqcA7.js → TemplateDetailPanel-B83bYkbT.js} +2 -2
- package/dist/{TemplatesPage-omZCh0-D.js → TemplatesPage-WTy20LXZ.js} +5 -5
- package/dist/{VersionDiffDialog-CLgIj_jc.js → VersionDiffDialog-BEIc5QBh.js} +1 -1
- package/dist/{WorkflowProposalCard-CV4kV4_Z.js → WorkflowProposalCard-KEvkgAE1.js} +1 -1
- package/dist/{WorkflowSearchRedirect-D34qC1Qm.js → WorkflowSearchRedirect-DB9R9UDy.js} +10 -10
- package/dist/{WorkflowShareDialog-DiD8Gqim.js → WorkflowShareDialog-C6icr074.js} +2 -2
- package/dist/{WorkflowsList-Bgsy1OPw.js → WorkflowsList-DZ_QxXEV.js} +5 -5
- package/dist/{agent-form-Ci_vxQF5.js → agent-form-hb7BR-JZ.js} +1 -1
- package/dist/{agentTools-D61qQFfw.js → agentTools-eOm3_v4A.js} +2 -2
- package/dist/{codec-client-Cm4GXmJ9.js → codec-client-B3ugmi-P.js} +1 -1
- package/dist/executions.js +1 -1
- package/dist/{flow-builder-sG8ZsMYV.js → flow-builder-B31fZz3L.js} +22 -22
- package/dist/history.js +1 -1
- package/dist/{index-FrgTpWov.d.ts → index-lX6U7gi1.d.ts} +67 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +24 -24
- package/dist/{node-detail-view-pyTakx4l.js → node-detail-view-DIR_J4IW.js} +6 -6
- package/dist/{node-endpoint-configs-DXCKkK_9.js → node-endpoint-configs-DS59aLlH.js} +560 -4
- package/dist/nodes.js +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +1 -1
- package/dist/{quick-config-panel-Zpsh2brj.js → quick-config-panel-iYkp65in.js} +2 -2
- package/dist/settings.js +1 -1
- package/dist/templates.js +1 -1
- package/dist/{useAgentDefinitions-Czl2aHJb.js → useAgentDefinitions-SRq-nq4y.js} +1 -1
- package/dist/{useExecutions-CZuOL3RI.js → useExecutions-D08C6QHV.js} +3 -2
- package/dist/{useObservability-D402nqXD.js → useObservability-111g9mWF.js} +2 -2
- package/dist/{useRunHistory-CsXQohcH.js → useRunHistory-DV-ad0I8.js} +2 -2
- package/dist/{useWorkflows-UyKrrkX-.js → useWorkflows-B0-aiUr8.js} +2 -2
- package/dist/workflow-builder.js +2 -2
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {
|
|
3
|
-
import { Vn as useContinuousOptimisationEnabled } from "./FluidGridsProvider-
|
|
2
|
+
import { Li as throwIfResultError, Rr as WorkflowProposalDocument, Rt as ProposeOptimisationDocument, S as ContinuousOptimisationSettingsDocument, Si as getFluidGridsClient, Sn as SetContinuousOptimisationEnabledDocument, Y as DismissOptimisationSuggestionDocument, dt as FgRunOptimisationScanDocument, jt as OptimisationSuggestionsDocument, kn as SnoozeOptimisationSuggestionDocument, tt as ErrorAnalyticsDocument, vi as WorkspaceAiUsageDocument } from "./node-endpoint-configs-DS59aLlH.js";
|
|
3
|
+
import { Vn as useContinuousOptimisationEnabled } from "./FluidGridsProvider-Bg6wKnX4.js";
|
|
4
4
|
import { r as useTr } from "./TranslationBridge-CX0OMnyn.js";
|
|
5
5
|
import { BC as OptimisationSuggestionStatus, RC as OptimisationDismissReason, fI as useFluidGridsPermission, lI as SdkPermissionButton, oI as FLUIDGRIDS_PERMISSIONS, zC as OptimisationKind } from "./graphql-types-CulUbQWN.js";
|
|
6
6
|
import { t as proposalCanvasPath } from "./useRequestedProposal-B7uPXfZB.js";
|
|
7
|
-
import { n as FailureTriagePanel } from "./FailureTriagePanel-
|
|
7
|
+
import { c as runListPath, l as utcDay, n as FailureTriagePanel } from "./FailureTriagePanel-D2RjCsYa.js";
|
|
8
8
|
import { a as formatTokens, c as DISMISS_REASONS, d as monthlySavingLabel, f as shortRunId, i as aiSpendPeriod, l as evidenceFacts, r as aiCost, s as runsOfWorkflowPath, t as AI_SPEND_RANGE_DAYS, u as evidenceWindowDays } from "./ai-usage-CK61EZWc.js";
|
|
9
|
-
import { n as useDataSinks, o as useRunReplayActions, r as useInsightsData, t as useDataSinkData } from "./useObservability-
|
|
9
|
+
import { n as useDataSinks, o as useRunReplayActions, r as useInsightsData, t as useDataSinkData } from "./useObservability-111g9mWF.js";
|
|
10
10
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
11
11
|
import { Link, useNavigate } from "react-router";
|
|
12
12
|
import { Icon } from "@iconify/react";
|
|
@@ -1285,6 +1285,306 @@ function SpendTable({ lines, tr }) {
|
|
|
1285
1285
|
});
|
|
1286
1286
|
}
|
|
1287
1287
|
|
|
1288
|
+
// src/modules/observability/components/ErrorAnalyticsPanel.tsx
|
|
1289
|
+
/**
|
|
1290
|
+
* Insights: the error panel (BOFF-9974). The workspace's failed runs over the
|
|
1291
|
+
* last 30 days, from `errorAnalytics`: how many failed each day, by error type,
|
|
1292
|
+
* the node types that failed most and the workflows that failed most.
|
|
1293
|
+
*
|
|
1294
|
+
* Every bar and row opens the Runs list on the failed runs behind it, over the
|
|
1295
|
+
* same window the panel counted (a day bar on that UTC day). The panel loads
|
|
1296
|
+
* and fails on its own, so the rest of Insights never waits for it.
|
|
1297
|
+
*/
|
|
1298
|
+
/** A bar's share of the largest value, never thinner than a visible sliver. */
|
|
1299
|
+
function barWidth(value, largest) {
|
|
1300
|
+
return `${Math.max(8, percentage(value, largest || 1))}%`;
|
|
1301
|
+
}
|
|
1302
|
+
function Ranking({ title, empty, children, testId }) {
|
|
1303
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1304
|
+
className: "rounded-lg border border-border-secondary bg-background-primary p-4",
|
|
1305
|
+
"data-testid": testId,
|
|
1306
|
+
children: [/* @__PURE__ */ jsx("h3", {
|
|
1307
|
+
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
1308
|
+
children: title
|
|
1309
|
+
}), children.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
1310
|
+
className: "space-y-1",
|
|
1311
|
+
children
|
|
1312
|
+
}) : /* @__PURE__ */ jsx("p", {
|
|
1313
|
+
className: "text-sm text-text-secondary",
|
|
1314
|
+
children: empty
|
|
1315
|
+
})]
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
function RankingRow({ to, label, detail, count, largest, tone }) {
|
|
1319
|
+
return /* @__PURE__ */ jsx("li", { children: /* @__PURE__ */ jsxs(Link, {
|
|
1320
|
+
to,
|
|
1321
|
+
className: "flex items-center gap-3 rounded-md px-2 py-1.5 hover:bg-background-tertiary",
|
|
1322
|
+
"data-testid": "error-panel-row",
|
|
1323
|
+
children: [
|
|
1324
|
+
/* @__PURE__ */ jsxs("span", {
|
|
1325
|
+
className: "min-w-0 flex-1",
|
|
1326
|
+
children: [/* @__PURE__ */ jsx("span", {
|
|
1327
|
+
className: "block truncate text-sm text-text-primary",
|
|
1328
|
+
children: label
|
|
1329
|
+
}), detail && /* @__PURE__ */ jsx("span", {
|
|
1330
|
+
className: "block truncate text-xs text-text-secondary",
|
|
1331
|
+
children: detail
|
|
1332
|
+
})]
|
|
1333
|
+
}),
|
|
1334
|
+
/* @__PURE__ */ jsx("span", {
|
|
1335
|
+
className: "h-2 w-24 shrink-0 overflow-hidden rounded-full bg-background-tertiary",
|
|
1336
|
+
children: /* @__PURE__ */ jsx("span", {
|
|
1337
|
+
className: `block h-full rounded-full ${tone === "error" ? "bg-status-error-bg" : "bg-status-warning-bg"}`,
|
|
1338
|
+
style: { width: barWidth(count, largest) }
|
|
1339
|
+
})
|
|
1340
|
+
}),
|
|
1341
|
+
/* @__PURE__ */ jsx("span", {
|
|
1342
|
+
className: "w-8 shrink-0 text-right text-sm font-medium text-text-secondary",
|
|
1343
|
+
children: count.toLocaleString()
|
|
1344
|
+
})
|
|
1345
|
+
]
|
|
1346
|
+
}) });
|
|
1347
|
+
}
|
|
1348
|
+
function Trend({ trend, link, tr }) {
|
|
1349
|
+
const largest = Math.max(0, ...trend.map((point) => point.count));
|
|
1350
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
1351
|
+
className: "rounded-lg border border-border-secondary bg-background-primary p-4",
|
|
1352
|
+
"data-testid": "error-panel-trend",
|
|
1353
|
+
children: [
|
|
1354
|
+
/* @__PURE__ */ jsx("h3", {
|
|
1355
|
+
className: "mb-3 text-sm font-semibold text-text-primary",
|
|
1356
|
+
children: tr("fluidgrids.insights.errorPanel.trend", "Failed runs per day")
|
|
1357
|
+
}),
|
|
1358
|
+
/* @__PURE__ */ jsx("ol", {
|
|
1359
|
+
className: "flex h-24 items-end gap-0.5",
|
|
1360
|
+
children: trend.map((point) => {
|
|
1361
|
+
const label = tr("fluidgrids.insights.errorPanel.trendDay", "{{date}}: {{count}} failed", {
|
|
1362
|
+
date: point.date,
|
|
1363
|
+
count: point.count.toLocaleString()
|
|
1364
|
+
});
|
|
1365
|
+
const height = point.count > 0 ? `${Math.max(6, percentage(point.count, largest))}%` : "2px";
|
|
1366
|
+
const day = utcDay(point.date);
|
|
1367
|
+
return /* @__PURE__ */ jsx("li", {
|
|
1368
|
+
className: "flex h-full min-w-0 flex-1 items-end",
|
|
1369
|
+
children: point.count > 0 && day ? /* @__PURE__ */ jsx(Link, {
|
|
1370
|
+
to: link({
|
|
1371
|
+
from: day.from,
|
|
1372
|
+
to: day.to
|
|
1373
|
+
}),
|
|
1374
|
+
className: "block w-full rounded-t-sm bg-status-error-bg hover:opacity-80",
|
|
1375
|
+
style: { height },
|
|
1376
|
+
title: label,
|
|
1377
|
+
"aria-label": label,
|
|
1378
|
+
"data-testid": "error-panel-day"
|
|
1379
|
+
}) : /* @__PURE__ */ jsx("span", {
|
|
1380
|
+
className: "block w-full rounded-t-sm bg-background-tertiary",
|
|
1381
|
+
style: { height },
|
|
1382
|
+
title: label
|
|
1383
|
+
})
|
|
1384
|
+
}, point.date);
|
|
1385
|
+
})
|
|
1386
|
+
}),
|
|
1387
|
+
trend.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
1388
|
+
className: "mt-1 flex justify-between text-xs text-text-secondary",
|
|
1389
|
+
children: [/* @__PURE__ */ jsx("span", { children: trend[0]?.date }), /* @__PURE__ */ jsx("span", { children: trend[trend.length - 1]?.date })]
|
|
1390
|
+
})
|
|
1391
|
+
]
|
|
1392
|
+
});
|
|
1393
|
+
}
|
|
1394
|
+
function ErrorAnalyticsPanel({ analytics, period, loading, error, onRetry }) {
|
|
1395
|
+
const tr = useTr();
|
|
1396
|
+
const link = (extra) => runListPath({
|
|
1397
|
+
status: "FAILED",
|
|
1398
|
+
from: period?.from,
|
|
1399
|
+
to: period?.to,
|
|
1400
|
+
...extra
|
|
1401
|
+
});
|
|
1402
|
+
let body;
|
|
1403
|
+
if (error && !analytics) body = /* @__PURE__ */ jsxs("div", {
|
|
1404
|
+
className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle p-4 text-sm text-status-error-text",
|
|
1405
|
+
role: "alert",
|
|
1406
|
+
children: [
|
|
1407
|
+
/* @__PURE__ */ jsx("p", {
|
|
1408
|
+
className: "font-medium",
|
|
1409
|
+
children: tr("fluidgrids.insights.errorPanel.loadError", "Could not load error analytics")
|
|
1410
|
+
}),
|
|
1411
|
+
/* @__PURE__ */ jsx("p", {
|
|
1412
|
+
className: "mt-1",
|
|
1413
|
+
children: error
|
|
1414
|
+
}),
|
|
1415
|
+
/* @__PURE__ */ jsx(Button$1, {
|
|
1416
|
+
variant: "outline",
|
|
1417
|
+
size: "sm",
|
|
1418
|
+
className: "mt-3",
|
|
1419
|
+
onClick: onRetry,
|
|
1420
|
+
children: tr("fluidgrids.insights.retryLoad", "Try again")
|
|
1421
|
+
})
|
|
1422
|
+
]
|
|
1423
|
+
});
|
|
1424
|
+
else if (!analytics) body = /* @__PURE__ */ jsx("div", {
|
|
1425
|
+
className: "h-40 animate-pulse rounded-lg bg-background-tertiary",
|
|
1426
|
+
"aria-busy": "true"
|
|
1427
|
+
});
|
|
1428
|
+
else if (analytics.totalErrors === 0) body = /* @__PURE__ */ jsx("p", {
|
|
1429
|
+
className: "text-sm text-text-secondary",
|
|
1430
|
+
children: tr("fluidgrids.insights.noErrors", "No errors in this period.")
|
|
1431
|
+
});
|
|
1432
|
+
else {
|
|
1433
|
+
const byType = [...analytics.errorsByType].sort((a, b) => b.count - a.count);
|
|
1434
|
+
const largestType = byType[0]?.count ?? 0;
|
|
1435
|
+
const largestNode = analytics.topFailingNodes[0]?.failureCount ?? 0;
|
|
1436
|
+
const largestWorkflow = analytics.topFailingWorkflows[0]?.failureCount ?? 0;
|
|
1437
|
+
body = /* @__PURE__ */ jsxs("div", {
|
|
1438
|
+
className: "space-y-4",
|
|
1439
|
+
children: [/* @__PURE__ */ jsx(Trend, {
|
|
1440
|
+
trend: analytics.trend,
|
|
1441
|
+
link,
|
|
1442
|
+
tr
|
|
1443
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
1444
|
+
className: "grid gap-4 lg:grid-cols-3",
|
|
1445
|
+
children: [
|
|
1446
|
+
/* @__PURE__ */ jsx(Ranking, {
|
|
1447
|
+
title: tr("fluidgrids.insights.errorsByType", "Errors by type"),
|
|
1448
|
+
empty: tr("fluidgrids.insights.noErrors", "No errors in this period."),
|
|
1449
|
+
testId: "error-panel-types",
|
|
1450
|
+
children: byType.map((entry) => /* @__PURE__ */ jsx(RankingRow, {
|
|
1451
|
+
to: link({ errorType: entry.errorType }),
|
|
1452
|
+
label: entry.errorType,
|
|
1453
|
+
count: entry.count,
|
|
1454
|
+
largest: largestType,
|
|
1455
|
+
tone: "error"
|
|
1456
|
+
}, entry.errorType))
|
|
1457
|
+
}),
|
|
1458
|
+
/* @__PURE__ */ jsx(Ranking, {
|
|
1459
|
+
title: tr("fluidgrids.insights.topFailingNodes", "Top failing nodes"),
|
|
1460
|
+
empty: tr("fluidgrids.insights.noFailedNodes", "No node failures in this period."),
|
|
1461
|
+
testId: "error-panel-nodes",
|
|
1462
|
+
children: analytics.topFailingNodes.map((node) => /* @__PURE__ */ jsx(RankingRow, {
|
|
1463
|
+
to: link({ failedNodeType: node.nodeType }),
|
|
1464
|
+
label: node.nodeType,
|
|
1465
|
+
detail: node.sampleError ?? tr("fluidgrids.insights.errorPanel.nodeRate", "{{failures}} of {{total}} executions failed", {
|
|
1466
|
+
failures: node.failureCount.toLocaleString(),
|
|
1467
|
+
total: node.totalExecutions.toLocaleString()
|
|
1468
|
+
}),
|
|
1469
|
+
count: node.failureCount,
|
|
1470
|
+
largest: largestNode,
|
|
1471
|
+
tone: "warning"
|
|
1472
|
+
}, node.nodeType))
|
|
1473
|
+
}),
|
|
1474
|
+
/* @__PURE__ */ jsx(Ranking, {
|
|
1475
|
+
title: tr("fluidgrids.insights.topFailingWorkflows", "Top failing workflows"),
|
|
1476
|
+
empty: tr("fluidgrids.insights.noFailedWorkflows", "No failed workflows in this period."),
|
|
1477
|
+
testId: "error-panel-workflows",
|
|
1478
|
+
children: analytics.topFailingWorkflows.map((workflow) => /* @__PURE__ */ jsx(RankingRow, {
|
|
1479
|
+
to: link({ workflowKey: workflow.workflowKey }),
|
|
1480
|
+
label: workflow.name?.trim() || workflow.workflowKey,
|
|
1481
|
+
detail: tr("fluidgrids.insights.errorPanel.workflowRate", "{{failures}} of {{total}} runs failed", {
|
|
1482
|
+
failures: workflow.failureCount.toLocaleString(),
|
|
1483
|
+
total: workflow.totalRuns.toLocaleString()
|
|
1484
|
+
}),
|
|
1485
|
+
count: workflow.failureCount,
|
|
1486
|
+
largest: largestWorkflow,
|
|
1487
|
+
tone: "error"
|
|
1488
|
+
}, workflow.workflowKey))
|
|
1489
|
+
})
|
|
1490
|
+
]
|
|
1491
|
+
})]
|
|
1492
|
+
});
|
|
1493
|
+
}
|
|
1494
|
+
return /* @__PURE__ */ jsxs("section", {
|
|
1495
|
+
className: "rounded-xl border border-border-secondary bg-background-secondary p-5",
|
|
1496
|
+
"aria-labelledby": "insights-error-panel-heading",
|
|
1497
|
+
"aria-busy": loading,
|
|
1498
|
+
"data-testid": "insights-error-panel",
|
|
1499
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1500
|
+
className: "mb-4 flex flex-wrap items-baseline justify-between gap-2",
|
|
1501
|
+
children: [/* @__PURE__ */ jsxs("div", { children: [/* @__PURE__ */ jsxs("h2", {
|
|
1502
|
+
id: "insights-error-panel-heading",
|
|
1503
|
+
className: "flex items-center gap-2 text-base font-semibold text-text-primary",
|
|
1504
|
+
children: [/* @__PURE__ */ jsx(Icon, {
|
|
1505
|
+
icon: "mdi:alert-octagon-outline",
|
|
1506
|
+
width: 18
|
|
1507
|
+
}), tr("fluidgrids.insights.errorPanel.title", "Errors")]
|
|
1508
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
1509
|
+
className: "mt-1 text-sm text-text-secondary",
|
|
1510
|
+
children: tr("fluidgrids.insights.errorPanel.subtitle", "Failed runs in the last 30 days. Select a bar or a row to see the runs behind it.")
|
|
1511
|
+
})] }), analytics && analytics.totalErrors > 0 && /* @__PURE__ */ jsx(Link, {
|
|
1512
|
+
to: link({}),
|
|
1513
|
+
className: "text-sm font-medium text-text-link hover:underline",
|
|
1514
|
+
"data-testid": "error-panel-total",
|
|
1515
|
+
children: tr("fluidgrids.insights.errorPanel.total", "{{count}} failed runs", { count: analytics.totalErrors.toLocaleString() })
|
|
1516
|
+
})]
|
|
1517
|
+
}), body]
|
|
1518
|
+
});
|
|
1519
|
+
}
|
|
1520
|
+
|
|
1521
|
+
// src/modules/observability/hooks/useErrorAnalytics.ts
|
|
1522
|
+
/**
|
|
1523
|
+
* useErrorAnalytics — the workspace's failed runs over the last
|
|
1524
|
+
* {@link ERROR_ANALYTICS_WINDOW_DAYS} days by type, node, workflow and day
|
|
1525
|
+
* (`errorAnalytics`, BOFF-7519), for the Insights error panel (BOFF-9974).
|
|
1526
|
+
*
|
|
1527
|
+
* The window is fixed when the read is made and returned with the data, so
|
|
1528
|
+
* the panel's links open the runs list on exactly the window it counted. A
|
|
1529
|
+
* plain network read per refresh; nothing is read while `enabled` is false.
|
|
1530
|
+
*/
|
|
1531
|
+
/** Rows per ranking. */
|
|
1532
|
+
const ERROR_ANALYTICS_LIMIT = 8;
|
|
1533
|
+
function errorAnalyticsWindow(now) {
|
|
1534
|
+
return {
|
|
1535
|
+
from: /* @__PURE__ */ new Date(now.getTime() - 2592e6),
|
|
1536
|
+
to: now
|
|
1537
|
+
};
|
|
1538
|
+
}
|
|
1539
|
+
async function fetchErrorAnalytics(period) {
|
|
1540
|
+
const result = await getFluidGridsClient().query({
|
|
1541
|
+
query: ErrorAnalyticsDocument,
|
|
1542
|
+
variables: { input: {
|
|
1543
|
+
startDate: period.from.toISOString(),
|
|
1544
|
+
endDate: period.to.toISOString(),
|
|
1545
|
+
limit: 8
|
|
1546
|
+
} },
|
|
1547
|
+
fetchPolicy: "network-only"
|
|
1548
|
+
});
|
|
1549
|
+
throwIfResultError(result);
|
|
1550
|
+
return result.data?.errorAnalytics ?? null;
|
|
1551
|
+
}
|
|
1552
|
+
function useErrorAnalytics(enabled) {
|
|
1553
|
+
const [sent, setSent] = useState(0);
|
|
1554
|
+
const [settled, setSettled] = useState(null);
|
|
1555
|
+
const request = useRef(0);
|
|
1556
|
+
const read = useCallback(async () => {
|
|
1557
|
+
if (!enabled) return;
|
|
1558
|
+
const id = ++request.current;
|
|
1559
|
+
setSent(id);
|
|
1560
|
+
const period = errorAnalyticsWindow(/* @__PURE__ */ new Date());
|
|
1561
|
+
let analytics = null;
|
|
1562
|
+
let error = null;
|
|
1563
|
+
try {
|
|
1564
|
+
analytics = await fetchErrorAnalytics(period);
|
|
1565
|
+
} catch (err) {
|
|
1566
|
+
error = err instanceof Error ? err.message : String(err);
|
|
1567
|
+
}
|
|
1568
|
+
if (id !== request.current) return;
|
|
1569
|
+
setSettled((previous) => ({
|
|
1570
|
+
request: id,
|
|
1571
|
+
period: analytics || !previous ? period : previous.period,
|
|
1572
|
+
analytics: analytics ?? (error ? previous?.analytics ?? null : null),
|
|
1573
|
+
error
|
|
1574
|
+
}));
|
|
1575
|
+
}, [enabled]);
|
|
1576
|
+
useEffect(() => {
|
|
1577
|
+
read();
|
|
1578
|
+
}, [read]);
|
|
1579
|
+
return {
|
|
1580
|
+
analytics: settled?.analytics ?? null,
|
|
1581
|
+
period: settled?.period ?? null,
|
|
1582
|
+
loading: enabled && (settled?.request ?? -1) !== sent,
|
|
1583
|
+
error: settled?.error ?? null,
|
|
1584
|
+
refetch: read
|
|
1585
|
+
};
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1288
1588
|
// src/modules/observability/pages/InsightsPage.tsx
|
|
1289
1589
|
function normalizedRate(summary) {
|
|
1290
1590
|
const supplied = summary.workflowSuccessRate;
|
|
@@ -1334,6 +1634,7 @@ function InsightsPage({ showErrors = false }) {
|
|
|
1334
1634
|
const { allowed: canManageTriage } = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.WORKFLOW_PUBLISH);
|
|
1335
1635
|
const { allowed: canRetryRuns } = useFluidGridsPermission(FLUIDGRIDS_PERMISSIONS.WORKFLOW_RUN_EXECUTE);
|
|
1336
1636
|
const [activeTab, setActiveTab] = useState(showErrors ? "errors" : "overview");
|
|
1637
|
+
const errorAnalytics = useErrorAnalytics(activeTab === "errors");
|
|
1337
1638
|
const failureBreakdown = useMemo(() => getFailureBreakdown(failedRuns), [failedRuns]);
|
|
1338
1639
|
const topWorkflows = useMemo(() => getTopFailingWorkflows(failedRuns).slice(0, 8), [failedRuns]);
|
|
1339
1640
|
const topNodes = useMemo(() => getTopFailingNodes(summary?.nodeUsageStats ?? []).slice(0, 8), [summary?.nodeUsageStats]);
|
|
@@ -1394,7 +1695,10 @@ function InsightsPage({ showErrors = false }) {
|
|
|
1394
1695
|
})
|
|
1395
1696
|
] }), /* @__PURE__ */ jsxs(Button$1, {
|
|
1396
1697
|
variant: "outline",
|
|
1397
|
-
onClick: () =>
|
|
1698
|
+
onClick: () => {
|
|
1699
|
+
refetch();
|
|
1700
|
+
if (activeTab === "errors") errorAnalytics.refetch();
|
|
1701
|
+
},
|
|
1398
1702
|
disabled: loading,
|
|
1399
1703
|
children: [/* @__PURE__ */ jsx(Icon, {
|
|
1400
1704
|
icon: "mdi:refresh",
|
|
@@ -1455,10 +1759,16 @@ function InsightsPage({ showErrors = false }) {
|
|
|
1455
1759
|
}) : /* @__PURE__ */ jsx(ErrorContent, {
|
|
1456
1760
|
summary,
|
|
1457
1761
|
failedRuns,
|
|
1458
|
-
failureBreakdown,
|
|
1459
1762
|
commonError,
|
|
1460
1763
|
retry,
|
|
1461
1764
|
retryLoading,
|
|
1765
|
+
errorPanel: /* @__PURE__ */ jsx(ErrorAnalyticsPanel, {
|
|
1766
|
+
analytics: errorAnalytics.analytics,
|
|
1767
|
+
period: errorAnalytics.period,
|
|
1768
|
+
loading: errorAnalytics.loading,
|
|
1769
|
+
error: errorAnalytics.error,
|
|
1770
|
+
onRetry: () => void errorAnalytics.refetch()
|
|
1771
|
+
}),
|
|
1462
1772
|
tr
|
|
1463
1773
|
})
|
|
1464
1774
|
]
|
|
@@ -1575,73 +1885,43 @@ function InsightList({ title, empty, children }) {
|
|
|
1575
1885
|
})]
|
|
1576
1886
|
});
|
|
1577
1887
|
}
|
|
1578
|
-
function ErrorContent({ summary, failedRuns,
|
|
1888
|
+
function ErrorContent({ summary, failedRuns, commonError, retry, retryLoading, errorPanel, tr }) {
|
|
1579
1889
|
return /* @__PURE__ */ jsxs("div", {
|
|
1580
1890
|
className: "space-y-6",
|
|
1581
1891
|
"data-tour": "fluidgrids-insights-errors",
|
|
1582
|
-
children: [
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1610
|
-
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
children: [/* @__PURE__ */ jsx("h2", {
|
|
1616
|
-
className: "mb-4 text-base font-semibold text-text-primary",
|
|
1617
|
-
children: tr("fluidgrids.insights.errorsByType", "Errors by type")
|
|
1618
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
1619
|
-
className: "space-y-3",
|
|
1620
|
-
children: [failureBreakdown.length === 0 && /* @__PURE__ */ jsx("p", {
|
|
1621
|
-
className: "text-sm text-text-secondary",
|
|
1622
|
-
children: tr("fluidgrids.insights.noErrors", "No errors in this period.")
|
|
1623
|
-
}), failureBreakdown.map((entry) => /* @__PURE__ */ jsxs("div", {
|
|
1624
|
-
className: "flex items-center gap-3",
|
|
1625
|
-
children: [
|
|
1626
|
-
/* @__PURE__ */ jsx("span", {
|
|
1627
|
-
className: "w-28 truncate text-sm text-text-secondary",
|
|
1628
|
-
children: entry.key
|
|
1629
|
-
}),
|
|
1630
|
-
/* @__PURE__ */ jsx("div", {
|
|
1631
|
-
className: "h-2 flex-1 overflow-hidden rounded-full bg-background-tertiary",
|
|
1632
|
-
children: /* @__PURE__ */ jsx("div", {
|
|
1633
|
-
className: "h-full rounded-full bg-status-error-bg",
|
|
1634
|
-
style: { width: `${Math.max(8, percentage(entry.count, failureBreakdown[0]?.count ?? 1))}%` }
|
|
1635
|
-
})
|
|
1636
|
-
}),
|
|
1637
|
-
/* @__PURE__ */ jsx("span", {
|
|
1638
|
-
className: "w-8 text-right text-sm font-medium text-text-primary",
|
|
1639
|
-
children: entry.count
|
|
1640
|
-
})
|
|
1641
|
-
]
|
|
1642
|
-
}, entry.key))]
|
|
1643
|
-
})]
|
|
1644
|
-
}), /* @__PURE__ */ jsxs("div", {
|
|
1892
|
+
children: [
|
|
1893
|
+
/* @__PURE__ */ jsxs("section", {
|
|
1894
|
+
className: "grid gap-4 sm:grid-cols-2 lg:grid-cols-4",
|
|
1895
|
+
children: [
|
|
1896
|
+
/* @__PURE__ */ jsx(MetricCard, {
|
|
1897
|
+
icon: "mdi:alert-outline",
|
|
1898
|
+
label: tr("fluidgrids.insights.failureRate", "Failure rate"),
|
|
1899
|
+
value: `${summary ? percentage(summary.runsFailedCount, summary.runsCountTotal).toFixed(1) : "0.0"}%`,
|
|
1900
|
+
tone: "text-status-error-text"
|
|
1901
|
+
}),
|
|
1902
|
+
/* @__PURE__ */ jsx(MetricCard, {
|
|
1903
|
+
icon: "mdi:counter",
|
|
1904
|
+
label: tr("fluidgrids.insights.failureCount", "Failures captured"),
|
|
1905
|
+
value: failedRuns.length.toLocaleString(),
|
|
1906
|
+
detail: summary ? `${summary.runsFailedCount.toLocaleString()} total recorded` : void 0
|
|
1907
|
+
}),
|
|
1908
|
+
/* @__PURE__ */ jsx(MetricCard, {
|
|
1909
|
+
icon: "mdi:alert-decagram-outline",
|
|
1910
|
+
label: tr("fluidgrids.insights.commonError", "Most common error"),
|
|
1911
|
+
value: commonError?.key ?? "—",
|
|
1912
|
+
detail: commonError ? `${commonError.count} occurrences` : void 0
|
|
1913
|
+
}),
|
|
1914
|
+
/* @__PURE__ */ jsx(MetricCard, {
|
|
1915
|
+
icon: "mdi:repeat",
|
|
1916
|
+
label: tr("fluidgrids.insights.recoveredByRetry", "Recovered by retry"),
|
|
1917
|
+
value: "—",
|
|
1918
|
+
detail: tr("fluidgrids.insights.retryBaselineMissing", "Retry recovery baseline is not exposed by the service yet."),
|
|
1919
|
+
tone: "text-text-secondary"
|
|
1920
|
+
})
|
|
1921
|
+
]
|
|
1922
|
+
}),
|
|
1923
|
+
errorPanel,
|
|
1924
|
+
/* @__PURE__ */ jsx("section", { children: /* @__PURE__ */ jsxs("div", {
|
|
1645
1925
|
className: "rounded-xl border border-border-secondary bg-background-secondary p-5",
|
|
1646
1926
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1647
1927
|
className: "mb-4 flex items-center justify-between gap-3",
|
|
@@ -1692,8 +1972,8 @@ function ErrorContent({ summary, failedRuns, failureBreakdown, commonError, retr
|
|
|
1692
1972
|
]
|
|
1693
1973
|
}, run.id))]
|
|
1694
1974
|
})]
|
|
1695
|
-
})
|
|
1696
|
-
|
|
1975
|
+
}) })
|
|
1976
|
+
]
|
|
1697
1977
|
});
|
|
1698
1978
|
}
|
|
1699
1979
|
function ErrorAnalyticsPage() {
|