okengine 0.22.0 → 0.23.1
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/AGENTS.md +7 -0
- package/manifest.v1.schema.json +44 -0
- package/package.json +32 -19
- package/site/content/docs/ai/mcp.mdx +14 -10
- package/site/content/docs/ai/skills.mdx +1 -1
- package/site/content/docs/elements/ai/agents.mdx +61 -13
- package/site/content/docs/elements/ai/decide.mdx +536 -0
- package/site/content/docs/elements/ai/events.mdx +373 -0
- package/site/content/docs/elements/ai/index.mdx +9 -3
- package/site/content/docs/elements/ai/meta.json +1 -1
- package/site/content/docs/elements/ai/prompts.mdx +4 -2
- package/site/content/docs/elements/channel/index.mdx +4 -4
- package/site/content/docs/elements/channel/receipts.mdx +7 -5
- package/site/content/docs/elements/channel/sms.mdx +2 -1
- package/site/content/docs/elements/flow/index.mdx +22 -18
- package/site/content/docs/elements/gate/auth.mdx +4 -1
- package/site/content/docs/elements/signal/index.mdx +15 -14
- package/site/content/docs/elements/store/index.mdx +1 -1
- package/site/content/docs/elements/store/kv.mdx +5 -5
- package/site/content/docs/plugins/otp.mdx +3 -3
- package/site/content/docs/recipes/dragonfly.mdx +5 -5
- package/site/content/docs/recipes/index.mdx +6 -6
- package/site/content/docs/recipes/postgres.mdx +12 -8
- package/site/content/docs/recipes/redis.mdx +4 -4
- package/site/content/docs/reference/cli.mdx +2 -1
- package/site/content/docs/reference/configuration.mdx +9 -7
- package/site/content/docs/reference/fx.mdx +19 -10
- package/src/auth/api-key-sql.test.ts +44 -0
- package/src/auth/api-key-sql.ts +1 -0
- package/src/auth/api-keys.ts +30 -12
- package/src/auth/config.ts +6 -2
- package/src/auth/gate-auth.test.ts +20 -0
- package/src/auth/tenants.ts +17 -0
- package/src/cli/agents-md.test.ts +25 -0
- package/src/cli/ask-vault-gaps.test.ts +38 -1
- package/src/cli/ask-vault-gaps.ts +35 -2
- package/src/cli/decide.ts +174 -0
- package/src/cli/decision-lock-watch.test.ts +45 -0
- package/src/cli/decision-lock-watch.ts +51 -0
- package/src/cli/dev-app-runner.ts +34 -8
- package/src/cli/dev-auth-secret.test.ts +49 -0
- package/src/cli/dev-auth-secret.ts +49 -0
- package/src/cli/dev-hot.test.ts +41 -0
- package/src/cli/dev-hot.ts +48 -0
- package/src/cli/dev.test.ts +1 -1
- package/src/cli/dev.ts +24 -6
- package/src/cli/doctor-diff.test.ts +29 -1
- package/src/cli/doctor-diff.ts +35 -0
- package/src/cli/eval.ts +142 -1
- package/src/cli/index.ts +5 -0
- package/src/cli/load-config.images.test.ts +2 -2
- package/src/cli/load-config.ts +1 -1
- package/src/cli/manifest-pr-diff.ts +16 -0
- package/src/cli/mcp-from-console.ts +48 -0
- package/src/cli/registry.ts +35 -1
- package/src/client/agent.ts +307 -0
- package/src/client/transport.test.ts +20 -0
- package/src/client/transport.ts +2 -1
- package/src/client/types.ts +1 -1
- package/src/client-react/index.ts +7 -1
- package/src/client-react/use-agent-run.test.ts +271 -0
- package/src/client-react/use-agent-run.ts +193 -0
- package/src/compiler/ai-approval.test.ts +36 -0
- package/src/compiler/ai-repair.test.ts +22 -0
- package/src/compiler/decisions.extract.test.ts +164 -0
- package/src/compiler/effects-fetch.test.ts +77 -0
- package/src/compiler/effects-infer.ts +114 -17
- package/src/compiler/effects-join.test.ts +48 -0
- package/src/compiler/extract.test.ts +28 -0
- package/src/compiler/extract.ts +279 -13
- package/src/compiler/fx-index.ts +58 -4
- package/src/compiler/response.ts +35 -2
- package/src/config/index.ts +21 -3
- package/src/console/index.ts +1 -1
- package/src/console/server/ai-runs-flows.ts +269 -0
- package/src/console/server/ai-runs.test.ts +323 -0
- package/src/console/server/ai-runs.ts +562 -0
- package/src/console/server/ai.ts +12 -1
- package/src/console/server/app.ts +10 -1
- package/src/console/server/decisions-flows.ts +157 -0
- package/src/console/server/decisions.test.ts +66 -0
- package/src/console/server/decisions.ts +229 -0
- package/src/console/server/flows.ts +50 -2
- package/src/console/server/invoke-user-flow.ts +9 -0
- package/src/console/server/runs-ingest.ts +16 -0
- package/src/console/server/serve.ts +5 -0
- package/src/console/server/state.ts +25 -1
- package/src/console/server/store-stats.test.ts +47 -0
- package/src/console/server/store-stats.ts +92 -18
- package/src/console/ui-next/dist/assets/access-page-C_N4qvai.js +4 -0
- package/src/console/ui-next/dist/assets/{agent-disclosure-Bkohc_8X.js → agent-disclosure-Cq1TxniW.js} +1 -1
- package/src/console/ui-next/dist/assets/{cache-glyph-rL0lHxat.js → cache-glyph-BaI4uxZz.js} +1 -1
- package/src/console/ui-next/dist/assets/{call-pii-button-Deo4PP18.js → call-pii-button-DNyK7IIY.js} +1 -1
- package/src/console/ui-next/dist/assets/{collapsible-CoJ6amHf.js → collapsible-CRhBJMZR.js} +1 -1
- package/src/console/ui-next/dist/assets/confirm-sheet-DZfuJXP4.js +1 -0
- package/src/console/ui-next/dist/assets/copy-inline-button-BTjPVjRT.js +1 -0
- package/src/console/ui-next/dist/assets/decisions-page-D9twj8Xy.js +1 -0
- package/src/console/ui-next/dist/assets/detail-header-Dk5LipF6.js +1 -0
- package/src/console/ui-next/dist/assets/dropdown-menu-CRGrj5JU.js +1 -0
- package/src/console/ui-next/dist/assets/duration-tone-CsHWlVPU.js +9 -0
- package/src/console/ui-next/dist/assets/element-icons-C6t8Vlml.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-chrome-Dslh2yE8.js +1 -0
- package/src/console/ui-next/dist/assets/explorer-empty-CIVg7Jgb.js +1 -0
- package/src/console/ui-next/dist/assets/flows-page-ZaTJAhR9.js +1 -0
- package/src/console/ui-next/dist/assets/{highlighted-json-CPYBzDh0.js → highlighted-json-DQ-EMAfz.js} +1 -1
- package/src/console/ui-next/dist/assets/{http-method-DTPevKmM.js → http-method-Cn_Fl79s.js} +1 -1
- package/src/console/ui-next/dist/assets/index-BlrN49Hs.css +2 -0
- package/src/console/ui-next/dist/assets/index-CmRFeWdT.js +58 -0
- package/src/console/ui-next/dist/assets/observability-page-Cn6R_dXz.js +8 -0
- package/src/console/ui-next/dist/assets/{replica-lag-BM27lXld.js → replica-lag-Bx6EZhSe.js} +7 -7
- package/src/console/ui-next/dist/assets/request-meta-DmdiUrfh.js +1 -0
- package/src/console/ui-next/dist/assets/shortcut-keys-DTE1sjTC.js +1 -0
- package/src/console/ui-next/dist/assets/store-page-8P6vGXnn.js +41 -0
- package/src/console/ui-next/dist/assets/trace-detail-sheet-BfGvpFSv.js +2 -0
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CWdUHbc0.js +55 -0
- package/src/console/ui-next/dist/assets/units-page-CZOFZzay.js +1 -0
- package/src/console/ui-next/dist/assets/use-vault-list-BAyQG8Re.js +1 -0
- package/src/console/ui-next/dist/assets/vault-page-ki_ishmX.js +2 -0
- package/src/console/ui-next/dist/index.html +4 -3
- package/src/console/ui-next/seed-parked-approval.ts +126 -0
- package/src/console/ui-next/src/client.ts +224 -1
- package/src/console/ui-next/src/components/explorer/detail-header.tsx +9 -0
- package/src/console/ui-next/src/components/explorer/explorer-start-toggle.tsx +5 -1
- package/src/console/ui-next/src/components/ui/sheet-form.tsx +21 -12
- package/src/console/ui-next/src/features/flows/decisions/decisions-page.tsx +216 -0
- package/src/console/ui-next/src/features/flows/decisions/resolve.test.ts +48 -0
- package/src/console/ui-next/src/features/flows/decisions/resolve.ts +111 -0
- package/src/console/ui-next/src/features/flows/flows-page.tsx +10 -0
- package/src/console/ui-next/src/features/flows/graph/element-map.ts +1 -0
- package/src/console/ui-next/src/features/flows/traces/effect-kind.ts +6 -0
- package/src/console/ui-next/src/features/flows/traces/effect-summary.test.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/effect-summary.ts +24 -0
- package/src/console/ui-next/src/features/flows/traces/http-status.ts +58 -0
- package/src/console/ui-next/src/features/flows/traces/request-client-card.tsx +355 -0
- package/src/console/ui-next/src/features/flows/traces/request-client.test.ts +114 -0
- package/src/console/ui-next/src/features/flows/traces/request-client.ts +423 -0
- package/src/console/ui-next/src/features/flows/traces/request-input-view.test.ts +52 -6
- package/src/console/ui-next/src/features/flows/traces/request-input-view.ts +85 -19
- package/src/console/ui-next/src/features/flows/traces/trace-detail-sheet.tsx +505 -80
- package/src/console/ui-next/src/features/flows/traces/trace-lanes.test.ts +61 -0
- package/src/console/ui-next/src/features/flows/traces/trace-lanes.ts +78 -0
- package/src/console/ui-next/src/features/flows/traces/trace-nav.test.ts +48 -0
- package/src/console/ui-next/src/features/flows/traces/trace-nav.ts +57 -0
- package/src/console/ui-next/src/features/flows/traces/trace-request-section.tsx +275 -96
- package/src/console/ui-next/src/features/flows/traces/traces-pane.tsx +16 -2
- package/src/console/ui-next/src/features/observability/detail/ai-runs.tsx +369 -0
- package/src/console/ui-next/src/features/observability/observability-page.tsx +31 -1
- package/src/console/ui-next/src/features/observability/state/observability-selection.ts +18 -3
- package/src/console/ui-next/src/features/store/performance/kv-performance-panel.tsx +12 -1
- package/src/console/ui-next/src/features/store/performance/performance-panel.tsx +14 -1
- package/src/console/ui-next/src/features/units/call/call-api-panel.tsx +1 -1
- package/src/console/ui-next/src/features/units/detail/flow-contract-panel.tsx +6 -2
- package/src/console/ui-next/src/features/units/explorer/units-tree.tsx +73 -18
- package/src/console/ui-next/src/features/units/lib/unit-tree.test.ts +21 -0
- package/src/console/ui-next/src/features/units/lib/unit-tree.ts +82 -0
- package/src/console/ui-next/src/features/units/units-page.tsx +25 -7
- package/src/console/ui-next/src/router.tsx +17 -0
- package/src/console/ui-next/ui-next-seed-runs.ts +23 -0
- package/src/console/ui-next/vite-console-kernel-plugin.ts +43 -3
- package/src/console/ui-next/vite.config.ts +9 -0
- package/src/docker/recipes/dragonfly.ts +3 -2
- package/src/docker/recipes/redis.ts +1 -1
- package/src/drivers/ai-anthropic.ts +212 -21
- package/src/drivers/ai-mock.ts +34 -1
- package/src/drivers/ai-openai-compatible.ts +67 -26
- package/src/drivers/ai-preconnect.ts +18 -0
- package/src/drivers/ai-stream.test.ts +62 -0
- package/src/drivers/ai-types.ts +20 -0
- package/src/drivers/journal-postgres.test.ts +22 -1
- package/src/drivers/journal-postgres.ts +511 -13
- package/src/drivers/memory-ddl.test.ts +18 -0
- package/src/drivers/memory.ts +21 -1
- package/src/drivers/pg-rls.test.ts +31 -0
- package/src/drivers/pg-rls.ts +15 -0
- package/src/drivers/postgres.test.ts +9 -0
- package/src/drivers/postgres.ts +49 -11
- package/src/drivers/signal-compete.test.ts +234 -0
- package/src/drivers/signal-postgres.ts +39 -19
- package/src/drivers/signal-redis.ts +167 -11
- package/src/drivers/signal-types.ts +12 -0
- package/src/elements/ai/agent-event-slot.ts +27 -0
- package/src/elements/ai/approval-http.ts +207 -0
- package/src/elements/ai/approval.test.ts +741 -0
- package/src/elements/ai/approval.ts +228 -0
- package/src/elements/ai/decisions/bind.ts +163 -0
- package/src/elements/ai/decisions/certificate.test.ts +291 -0
- package/src/elements/ai/decisions/certificate.ts +377 -0
- package/src/elements/ai/decisions/certify.ts +314 -0
- package/src/elements/ai/decisions/decide.test.ts +953 -0
- package/src/elements/ai/decisions/e2e.test.ts +399 -0
- package/src/elements/ai/decisions/export.test.ts +120 -0
- package/src/elements/ai/decisions/export.ts +146 -0
- package/src/elements/ai/decisions/fixtures/openrouter-request.json +24 -0
- package/src/elements/ai/decisions/fixtures/openrouter-response.json +22 -0
- package/src/elements/ai/decisions/fixtures/typesafe-request.json +19 -0
- package/src/elements/ai/decisions/fixtures/typesafe-response.json +13 -0
- package/src/elements/ai/decisions/http.test.ts +154 -0
- package/src/elements/ai/decisions/http.ts +240 -0
- package/src/elements/ai/decisions/labels.test.ts +282 -0
- package/src/elements/ai/decisions/labels.ts +257 -0
- package/src/elements/ai/decisions/openrouter.live.test.ts +136 -0
- package/src/elements/ai/decisions/openrouter.ts +36 -0
- package/src/elements/ai/decisions/provider.ts +102 -0
- package/src/elements/ai/decisions/typesafe.ts +36 -0
- package/src/elements/ai/declare.ts +252 -1
- package/src/elements/ai/events.test.ts +379 -0
- package/src/elements/ai/events.ts +138 -0
- package/src/elements/ai/mcp-protocol.ts +5 -6
- package/src/elements/ai/run-events.test.ts +461 -0
- package/src/elements/ai/run-events.ts +522 -0
- package/src/elements/ai/runtime.ts +1187 -105
- package/src/elements/ai/stream-turn.ts +214 -0
- package/src/elements/ai/stream.live.test.ts +76 -0
- package/src/elements/ai/subagent.test.ts +136 -0
- package/src/elements/ai.test.ts +497 -3
- package/src/elements/ai.ts +16 -1
- package/src/elements/channel/runtime.ts +11 -0
- package/src/elements/channel/sql-ledger.ts +251 -0
- package/src/elements/clock/durable.ts +27 -1
- package/src/elements/signal/runtime.ts +9 -0
- package/src/elements/signal.test.ts +1 -0
- package/src/elements/store/cache.test.ts +120 -15
- package/src/elements/store/cache.ts +200 -39
- package/src/elements/store/prepare-row.test.ts +6 -2
- package/src/elements/store/sql-session.test.ts +53 -0
- package/src/elements/store/sql-session.ts +206 -10
- package/src/elements/store.ts +1 -0
- package/src/i18n/catalogs/ar.ts +5 -0
- package/src/i18n/catalogs/en.ts +5 -0
- package/src/index.ts +2 -0
- package/src/kernel/agent-event-store.ts +448 -0
- package/src/kernel/app.ts +135 -17
- package/src/kernel/auto-cache.test.ts +228 -0
- package/src/kernel/boot-bind/ai.ts +3 -0
- package/src/kernel/boot-bind/channel.ts +63 -2
- package/src/kernel/boot-bind/honor-config.test.ts +40 -10
- package/src/kernel/boot-bind/signal.ts +61 -25
- package/src/kernel/boot-bind/store.test.ts +26 -0
- package/src/kernel/boot-bind/store.ts +82 -6
- package/src/kernel/boot.ts +31 -6
- package/src/kernel/builtin-errors.ts +2 -0
- package/src/kernel/capability.ts +3 -0
- package/src/kernel/decision-label-store.ts +441 -0
- package/src/kernel/effects.test.ts +2 -1
- package/src/kernel/effects.ts +13 -1
- package/src/kernel/element-registries.ts +3 -0
- package/src/kernel/errors-compiler.ts +11 -0
- package/src/kernel/errors-text.ts +20 -0
- package/src/kernel/errors.ts +10 -0
- package/src/kernel/flow.test.ts +2 -3
- package/src/kernel/flow.ts +33 -3
- package/src/kernel/fx-call-types.test.ts +32 -0
- package/src/kernel/fx-decide.ts +765 -0
- package/src/kernel/fx-sql-handle.ts +46 -7
- package/src/kernel/fx.test.ts +13 -8
- package/src/kernel/fx.ts +339 -45
- package/src/kernel/http-frame.test.ts +94 -0
- package/src/kernel/http-frame.ts +203 -0
- package/src/kernel/idempotency.test.ts +2 -1
- package/src/kernel/journal.test.ts +114 -0
- package/src/kernel/journal.ts +471 -51
- package/src/kernel/json-result.ts +10 -0
- package/src/kernel/pipeline-tenant.ts +5 -1
- package/src/kernel/pipeline.test.ts +45 -0
- package/src/kernel/pipeline.ts +5 -0
- package/src/kernel/signal-tx.ts +28 -0
- package/src/kernel/sse-id.ts +32 -0
- package/src/kernel/store-transaction.test.ts +95 -0
- package/src/manifest/diff.ts +1 -0
- package/src/manifest/types.ts +29 -2
- package/src/mcp/ai-tools.test.ts +202 -0
- package/src/mcp/authorization.ts +66 -0
- package/src/mcp/docs-server.ts +19 -2
- package/src/mcp/mcp.test.ts +83 -0
- package/src/mcp/protocol.ts +8 -2
- package/src/mcp/server.ts +23 -2
- package/src/mcp/session.ts +3 -0
- package/src/mcp/tools.ts +168 -0
- package/src/mcp/versions.ts +60 -0
- package/src/plugins/index.ts +1 -0
- package/src/plugins/mena.ts +56 -0
- package/src/release/http-graph.test.ts +2 -0
- package/src/release/http-graph.ts +5 -0
- package/src/release/measure.ts +39 -14
- package/src/runs/collect.ts +4 -1
- package/src/runs/parquet.test.ts +27 -1
- package/src/runs/parquet.ts +19 -0
- package/src/runs/types.ts +31 -0
- package/src/runtime/json-code-block.test.ts +106 -47
- package/src/runtime/json-code-block.ts +1209 -46
- package/src/term.test.ts +13 -0
- package/src/term.ts +81 -49
- package/src/console/ui-next/dist/assets/PlusSignIcon-CwG3nxfu.js +0 -1
- package/src/console/ui-next/dist/assets/access-page-Ze6ckjdd.js +0 -4
- package/src/console/ui-next/dist/assets/copy-inline-button-CWG5_ZOh.js +0 -1
- package/src/console/ui-next/dist/assets/detail-header-b_ZzIsmU.js +0 -1
- package/src/console/ui-next/dist/assets/dropdown-menu-nwXEO1Ac.js +0 -1
- package/src/console/ui-next/dist/assets/duration-tone-BbQ_8z50.js +0 -9
- package/src/console/ui-next/dist/assets/element-icons-CwyLpVXz.js +0 -1
- package/src/console/ui-next/dist/assets/explorer-empty-C8sSCqYT.js +0 -1
- package/src/console/ui-next/dist/assets/flows-page-D2E7BtKK.js +0 -1
- package/src/console/ui-next/dist/assets/index-VxoEz295.css +0 -2
- package/src/console/ui-next/dist/assets/index-vTuwmeQz.js +0 -58
- package/src/console/ui-next/dist/assets/observability-page-SJTSzHFJ.js +0 -4
- package/src/console/ui-next/dist/assets/request-meta-BjFT7DNl.js +0 -1
- package/src/console/ui-next/dist/assets/shortcut-keys-CUNegEV4.js +0 -1
- package/src/console/ui-next/dist/assets/store-page-Qj9ThRE-.js +0 -41
- package/src/console/ui-next/dist/assets/trace-detail-sheet-Cmitq3da.js +0 -2
- package/src/console/ui-next/dist/assets/tree-expand-toggle-CbDIB-7x.js +0 -55
- package/src/console/ui-next/dist/assets/units-page-_PuYqFty.js +0 -1
- package/src/console/ui-next/dist/assets/use-vault-list-Cs45Czkt.js +0 -1
- package/src/console/ui-next/dist/assets/vault-page-BOMr0go9.js +0 -2
|
@@ -28,12 +28,16 @@ import { HighlightedJson } from "@/components/highlighted-json";
|
|
|
28
28
|
import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible";
|
|
29
29
|
import { Tooltip, TooltipContent, TooltipTrigger } from "@/components/ui/tooltip";
|
|
30
30
|
import { cn } from "@/lib/utils";
|
|
31
|
+
import type { RunHttpFrame } from "@/client.ts";
|
|
31
32
|
import { httpMethodBadgeClass, httpMethodRailClass } from "./http-method.ts";
|
|
33
|
+
import { RequestClientCard } from "./request-client-card.tsx";
|
|
34
|
+
import { httpStatusRailClass, httpStatusReason, httpStatusTextClass } from "./http-status.ts";
|
|
32
35
|
import {
|
|
33
36
|
fieldCopyText,
|
|
34
37
|
inputByteLabel,
|
|
35
38
|
inputFieldRows,
|
|
36
39
|
inputShapeHint,
|
|
40
|
+
payloadHasContent,
|
|
37
41
|
type InputFieldKind,
|
|
38
42
|
type InputFieldRow,
|
|
39
43
|
} from "./request-input-view.ts";
|
|
@@ -50,6 +54,11 @@ export type TraceRequestSectionProps = {
|
|
|
50
54
|
readonly input: unknown;
|
|
51
55
|
/** Projected run output snapshot. */
|
|
52
56
|
readonly output: unknown;
|
|
57
|
+
/**
|
|
58
|
+
* HTTP wire frame. `null` for non-HTTP runs and rows recorded before the
|
|
59
|
+
* frame existed — those still show the body only.
|
|
60
|
+
*/
|
|
61
|
+
readonly http: RunHttpFrame | null;
|
|
53
62
|
/** Declared / framework error code when the run failed. */
|
|
54
63
|
readonly error: string | null;
|
|
55
64
|
/** Optional human message paired with {@link error}. */
|
|
@@ -81,6 +90,7 @@ export function TraceRequestSection({
|
|
|
81
90
|
headline,
|
|
82
91
|
input,
|
|
83
92
|
output,
|
|
93
|
+
http,
|
|
84
94
|
error,
|
|
85
95
|
errorMessage,
|
|
86
96
|
inputOpen,
|
|
@@ -88,10 +98,19 @@ export function TraceRequestSection({
|
|
|
88
98
|
outputOpen,
|
|
89
99
|
onOutputOpenChange,
|
|
90
100
|
}: TraceRequestSectionProps): JSX.Element {
|
|
91
|
-
const
|
|
101
|
+
const shownMethod = http?.request.method ?? method;
|
|
102
|
+
const shownPath = http?.request.path ?? path;
|
|
103
|
+
const endpoint = shownMethod && shownPath ? `${shownMethod} ${shownPath}` : headline;
|
|
104
|
+
const query = http?.request.query ?? {};
|
|
105
|
+
const requestHeaders = http?.request.headers ?? {};
|
|
106
|
+
const hasQuery = Object.keys(query).length > 0;
|
|
107
|
+
const hasRequestHeaders = Object.keys(requestHeaders).length > 0;
|
|
108
|
+
const responseStatus = http?.response?.status;
|
|
109
|
+
const responseHeaders = http?.response?.headers ?? {};
|
|
110
|
+
const hasResponseHeaders = Object.keys(responseHeaders).length > 0;
|
|
92
111
|
const failed = error !== null;
|
|
93
|
-
const hasInput = input
|
|
94
|
-
const hasOutput = output
|
|
112
|
+
const hasInput = payloadHasContent(input);
|
|
113
|
+
const hasOutput = payloadHasContent(output);
|
|
95
114
|
const responseFills = outputOpen && !failed && hasOutput;
|
|
96
115
|
const requestFills = inputOpen && hasInput && !responseFills;
|
|
97
116
|
|
|
@@ -119,22 +138,55 @@ export function TraceRequestSection({
|
|
|
119
138
|
|
|
120
139
|
<div data-slot="trace-request-frame" className={requestFills ? FILL_COL_CLASS : undefined}>
|
|
121
140
|
<div className={cn("flex min-w-0", requestFills && "min-h-0 flex-1")}>
|
|
122
|
-
<MethodRail method={
|
|
141
|
+
<MethodRail method={shownMethod} />
|
|
123
142
|
<div className={cn("flex min-w-0 flex-1 flex-col", requestFills && "min-h-0")}>
|
|
124
|
-
<RequestEndpoint method={
|
|
125
|
-
<
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
143
|
+
<RequestEndpoint method={shownMethod} path={shownPath} headline={headline} />
|
|
144
|
+
{hasRequestHeaders ? <RequestClientCard headers={requestHeaders} /> : null}
|
|
145
|
+
{hasQuery ? (
|
|
146
|
+
<PayloadPanel
|
|
147
|
+
value={query}
|
|
148
|
+
open
|
|
149
|
+
onOpenChange={() => undefined}
|
|
150
|
+
label="Query"
|
|
151
|
+
empty=""
|
|
152
|
+
copyLabel="Copy query JSON"
|
|
153
|
+
copySlot="trace-request-copy-query"
|
|
154
|
+
toggleSlot="trace-request-query-toggle"
|
|
155
|
+
fieldsSlot="trace-request-query"
|
|
156
|
+
jsonSlot="trace-request-query-json"
|
|
157
|
+
localOpen
|
|
158
|
+
/>
|
|
159
|
+
) : null}
|
|
160
|
+
{hasRequestHeaders ? (
|
|
161
|
+
<PayloadPanel
|
|
162
|
+
value={requestHeaders}
|
|
163
|
+
open
|
|
164
|
+
onOpenChange={() => undefined}
|
|
165
|
+
label="Headers"
|
|
166
|
+
empty=""
|
|
167
|
+
copyLabel="Copy request headers"
|
|
168
|
+
copySlot="trace-request-copy-headers"
|
|
169
|
+
toggleSlot="trace-request-headers-toggle"
|
|
170
|
+
fieldsSlot="trace-request-headers"
|
|
171
|
+
jsonSlot="trace-request-headers-json"
|
|
172
|
+
localOpen
|
|
173
|
+
/>
|
|
174
|
+
) : null}
|
|
175
|
+
{hasInput ? (
|
|
176
|
+
<PayloadPanel
|
|
177
|
+
value={input}
|
|
178
|
+
open={inputOpen}
|
|
179
|
+
onOpenChange={onInputOpenChange}
|
|
180
|
+
label="Body"
|
|
181
|
+
empty=""
|
|
182
|
+
copyLabel="Copy body JSON"
|
|
183
|
+
copySlot="trace-request-copy-input"
|
|
184
|
+
toggleSlot="trace-input-toggle"
|
|
185
|
+
fieldsSlot="trace-request-fields"
|
|
186
|
+
jsonSlot="trace-input-json"
|
|
187
|
+
fill={requestFills}
|
|
188
|
+
/>
|
|
189
|
+
) : null}
|
|
138
190
|
</div>
|
|
139
191
|
</div>
|
|
140
192
|
</div>
|
|
@@ -150,7 +202,7 @@ export function TraceRequestSection({
|
|
|
150
202
|
<div className={EXPLORER_STRIP_CLASS}>
|
|
151
203
|
<h3 className={cn(SECTION_HEAD_CLASS, "flex items-center px-2")}>Response</h3>
|
|
152
204
|
<div className="ml-auto flex h-full items-stretch">
|
|
153
|
-
{!failed &&
|
|
205
|
+
{!failed && hasOutput ? (
|
|
154
206
|
<CopyIconButton
|
|
155
207
|
label="Copy response JSON"
|
|
156
208
|
text={JSON.stringify(output, null, 2)}
|
|
@@ -167,33 +219,8 @@ export function TraceRequestSection({
|
|
|
167
219
|
</div>
|
|
168
220
|
</div>
|
|
169
221
|
|
|
170
|
-
{failed ? (
|
|
171
|
-
<
|
|
172
|
-
<div className="flex min-w-0">
|
|
173
|
-
<div
|
|
174
|
-
className="w-1 shrink-0 self-stretch bg-destructive"
|
|
175
|
-
aria-hidden
|
|
176
|
-
data-slot="trace-response-rail"
|
|
177
|
-
/>
|
|
178
|
-
<div className="flex min-w-0 flex-1 flex-col gap-1 px-2.5 py-2.5">
|
|
179
|
-
<div className="flex items-center gap-1.5">
|
|
180
|
-
<HugeiconsIcon
|
|
181
|
-
icon={Alert02Icon}
|
|
182
|
-
className="size-3.5 shrink-0 text-destructive"
|
|
183
|
-
aria-hidden
|
|
184
|
-
/>
|
|
185
|
-
<span className="font-mono text-xs font-semibold text-destructive">{error}</span>
|
|
186
|
-
</div>
|
|
187
|
-
{errorMessage ? (
|
|
188
|
-
<p className="text-[11px] leading-snug text-destructive/90">{errorMessage}</p>
|
|
189
|
-
) : (
|
|
190
|
-
<p className="text-[11px] text-muted-foreground">
|
|
191
|
-
Run failed with this error code — no return value was stored.
|
|
192
|
-
</p>
|
|
193
|
-
)}
|
|
194
|
-
</div>
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
222
|
+
{failed && responseStatus === undefined ? (
|
|
223
|
+
<ResponseError error={error} errorMessage={errorMessage} />
|
|
197
224
|
) : (
|
|
198
225
|
<div
|
|
199
226
|
data-slot="trace-response-frame"
|
|
@@ -201,24 +228,49 @@ export function TraceRequestSection({
|
|
|
201
228
|
>
|
|
202
229
|
<div className={cn("flex min-w-0", responseFills && "min-h-0 flex-1")}>
|
|
203
230
|
<div
|
|
204
|
-
className=
|
|
231
|
+
className={cn(
|
|
232
|
+
"w-1 shrink-0 self-stretch",
|
|
233
|
+
responseStatus !== undefined
|
|
234
|
+
? httpStatusRailClass(responseStatus)
|
|
235
|
+
: "bg-emerald-500",
|
|
236
|
+
)}
|
|
205
237
|
aria-hidden
|
|
206
238
|
data-slot="trace-response-rail"
|
|
207
239
|
/>
|
|
208
240
|
<div className={cn("flex min-w-0 flex-1 flex-col", responseFills && "min-h-0")}>
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
241
|
+
{responseStatus !== undefined ? <ResponseStatus status={responseStatus} /> : null}
|
|
242
|
+
{hasResponseHeaders ? (
|
|
243
|
+
<PayloadPanel
|
|
244
|
+
value={responseHeaders}
|
|
245
|
+
open
|
|
246
|
+
onOpenChange={() => undefined}
|
|
247
|
+
label="Headers"
|
|
248
|
+
empty=""
|
|
249
|
+
copyLabel="Copy response headers"
|
|
250
|
+
copySlot="trace-response-copy-headers"
|
|
251
|
+
toggleSlot="trace-response-headers-toggle"
|
|
252
|
+
fieldsSlot="trace-response-headers"
|
|
253
|
+
jsonSlot="trace-response-headers-json"
|
|
254
|
+
localOpen
|
|
255
|
+
/>
|
|
256
|
+
) : null}
|
|
257
|
+
{failed ? (
|
|
258
|
+
<ResponseError error={error} errorMessage={errorMessage} bare />
|
|
259
|
+
) : hasOutput ? (
|
|
260
|
+
<PayloadPanel
|
|
261
|
+
value={output}
|
|
262
|
+
open={outputOpen}
|
|
263
|
+
onOpenChange={onOutputOpenChange}
|
|
264
|
+
label="Body"
|
|
265
|
+
empty=""
|
|
266
|
+
copyLabel="Copy response JSON"
|
|
267
|
+
copySlot="trace-response-copy-body"
|
|
268
|
+
toggleSlot="trace-response-toggle"
|
|
269
|
+
fieldsSlot="trace-response-fields"
|
|
270
|
+
jsonSlot="trace-response-json"
|
|
271
|
+
fill={responseFills}
|
|
272
|
+
/>
|
|
273
|
+
) : null}
|
|
222
274
|
</div>
|
|
223
275
|
</div>
|
|
224
276
|
</div>
|
|
@@ -228,6 +280,82 @@ export function TraceRequestSection({
|
|
|
228
280
|
);
|
|
229
281
|
}
|
|
230
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Status line for an HTTP response frame.
|
|
285
|
+
*
|
|
286
|
+
* @param props - Status code
|
|
287
|
+
*/
|
|
288
|
+
function ResponseStatus({ status }: { readonly status: number }): JSX.Element {
|
|
289
|
+
const reason = httpStatusReason(status);
|
|
290
|
+
return (
|
|
291
|
+
<div className="flex min-w-0 items-center gap-2 px-2.5 py-2" data-slot="trace-response-status">
|
|
292
|
+
<span
|
|
293
|
+
className={cn(
|
|
294
|
+
"shrink-0 font-mono text-[10px] font-semibold tabular-nums",
|
|
295
|
+
httpStatusTextClass(status),
|
|
296
|
+
)}
|
|
297
|
+
>
|
|
298
|
+
{status}
|
|
299
|
+
</span>
|
|
300
|
+
{reason ? <span className="font-mono text-xs text-foreground">{reason}</span> : null}
|
|
301
|
+
</div>
|
|
302
|
+
);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
/**
|
|
306
|
+
* Failed-run alert. `bare` sits inside a frame that already has a rail.
|
|
307
|
+
*
|
|
308
|
+
* @param props - Error code and optional message
|
|
309
|
+
*/
|
|
310
|
+
function ResponseError({
|
|
311
|
+
error,
|
|
312
|
+
errorMessage,
|
|
313
|
+
bare = false,
|
|
314
|
+
}: {
|
|
315
|
+
readonly error: string | null;
|
|
316
|
+
readonly errorMessage: string | null;
|
|
317
|
+
readonly bare?: boolean;
|
|
318
|
+
}): JSX.Element {
|
|
319
|
+
const body = (
|
|
320
|
+
<div className="flex min-w-0 flex-1 flex-col gap-1 px-2.5 py-2.5">
|
|
321
|
+
<div className="flex items-center gap-1.5">
|
|
322
|
+
<HugeiconsIcon
|
|
323
|
+
icon={Alert02Icon}
|
|
324
|
+
className="size-3.5 shrink-0 text-destructive"
|
|
325
|
+
aria-hidden
|
|
326
|
+
/>
|
|
327
|
+
<span className="font-mono text-xs font-semibold text-destructive">{error}</span>
|
|
328
|
+
</div>
|
|
329
|
+
{errorMessage ? (
|
|
330
|
+
<p className="text-[11px] leading-snug text-destructive/90">{errorMessage}</p>
|
|
331
|
+
) : (
|
|
332
|
+
<p className="text-[11px] text-muted-foreground">
|
|
333
|
+
Run failed with this error code — no return value was stored.
|
|
334
|
+
</p>
|
|
335
|
+
)}
|
|
336
|
+
</div>
|
|
337
|
+
);
|
|
338
|
+
if (bare) {
|
|
339
|
+
return (
|
|
340
|
+
<div data-slot="trace-response-error" role="alert" className="border-t border-border/60">
|
|
341
|
+
{body}
|
|
342
|
+
</div>
|
|
343
|
+
);
|
|
344
|
+
}
|
|
345
|
+
return (
|
|
346
|
+
<div data-slot="trace-response-error" role="alert">
|
|
347
|
+
<div className="flex min-w-0">
|
|
348
|
+
<div
|
|
349
|
+
className="w-1 shrink-0 self-stretch bg-destructive"
|
|
350
|
+
aria-hidden
|
|
351
|
+
data-slot="trace-response-rail"
|
|
352
|
+
/>
|
|
353
|
+
{body}
|
|
354
|
+
</div>
|
|
355
|
+
</div>
|
|
356
|
+
);
|
|
357
|
+
}
|
|
358
|
+
|
|
231
359
|
/**
|
|
232
360
|
* Collapsible Fields/Raw payload panel shared by Request and Output.
|
|
233
361
|
*
|
|
@@ -245,6 +373,7 @@ function PayloadPanel({
|
|
|
245
373
|
fieldsSlot,
|
|
246
374
|
jsonSlot,
|
|
247
375
|
fill = false,
|
|
376
|
+
localOpen = false,
|
|
248
377
|
}: {
|
|
249
378
|
readonly value: unknown;
|
|
250
379
|
readonly open: boolean;
|
|
@@ -258,6 +387,8 @@ function PayloadPanel({
|
|
|
258
387
|
readonly jsonSlot: string;
|
|
259
388
|
/** Grow to fill leftover sheet height instead of capping at 14rem. */
|
|
260
389
|
readonly fill?: boolean;
|
|
390
|
+
/** Own the open state, starting expanded. Used for query and headers. */
|
|
391
|
+
readonly localOpen?: boolean;
|
|
261
392
|
}): JSX.Element {
|
|
262
393
|
const hasValue = value !== null && value !== undefined;
|
|
263
394
|
const json = useMemo(() => (hasValue ? JSON.stringify(value, null, 2) : ""), [hasValue, value]);
|
|
@@ -265,6 +396,9 @@ function PayloadPanel({
|
|
|
265
396
|
const shapeHint = useMemo(() => (hasValue ? inputShapeHint(value) : null), [hasValue, value]);
|
|
266
397
|
const byteLabel = useMemo(() => (hasValue ? inputByteLabel(json) : null), [hasValue, json]);
|
|
267
398
|
const [view, setView] = useState<BodyView>(rows ? "fields" : "raw");
|
|
399
|
+
const [ownOpen, setOwnOpen] = useState(true);
|
|
400
|
+
const panelOpen = localOpen ? ownOpen : open;
|
|
401
|
+
const setPanelOpen = localOpen ? setOwnOpen : onOpenChange;
|
|
268
402
|
|
|
269
403
|
useEffect(() => {
|
|
270
404
|
setView(rows ? "fields" : "raw");
|
|
@@ -280,9 +414,9 @@ function PayloadPanel({
|
|
|
280
414
|
|
|
281
415
|
return (
|
|
282
416
|
<Collapsible
|
|
283
|
-
open={
|
|
284
|
-
onOpenChange={
|
|
285
|
-
className={fill ? FILL_COL_CLASS :
|
|
417
|
+
open={panelOpen}
|
|
418
|
+
onOpenChange={setPanelOpen}
|
|
419
|
+
className={fill ? FILL_COL_CLASS : "shrink-0"}
|
|
286
420
|
>
|
|
287
421
|
<div className={cn(EXPLORER_STRIP_CLASS, "border-t")}>
|
|
288
422
|
<CollapsibleTrigger
|
|
@@ -291,7 +425,7 @@ function PayloadPanel({
|
|
|
291
425
|
>
|
|
292
426
|
<HugeiconsIcon
|
|
293
427
|
icon={ArrowDown01Icon}
|
|
294
|
-
className={cn(EXPLORER_CHEVRON_CLASS, !
|
|
428
|
+
className={cn(EXPLORER_CHEVRON_CLASS, !panelOpen && "-rotate-90")}
|
|
295
429
|
/>
|
|
296
430
|
<span>{label}</span>
|
|
297
431
|
{shapeHint ? (
|
|
@@ -453,7 +587,7 @@ function ViewToggleButton({
|
|
|
453
587
|
}
|
|
454
588
|
|
|
455
589
|
/**
|
|
456
|
-
* Interactive key / value
|
|
590
|
+
* Interactive key / value tree. Objects and arrays expand into child fields.
|
|
457
591
|
*
|
|
458
592
|
* @param props - Projected field rows
|
|
459
593
|
*/
|
|
@@ -467,42 +601,87 @@ function FieldsTable({
|
|
|
467
601
|
return (
|
|
468
602
|
<ul data-slot={dataSlot}>
|
|
469
603
|
{rows.map((row) => (
|
|
470
|
-
<
|
|
471
|
-
key={row.key}
|
|
472
|
-
className={cn(EXPLORER_ROW_CLASS, "group/field items-start")}
|
|
473
|
-
data-slot="trace-payload-field"
|
|
474
|
-
>
|
|
475
|
-
<div className="flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:gap-3">
|
|
476
|
-
<span className="w-[7.5rem] shrink-0 truncate font-mono text-[11px] font-medium text-sky-600 dark:text-sky-400">
|
|
477
|
-
{row.key}
|
|
478
|
-
</span>
|
|
479
|
-
<span
|
|
480
|
-
className={cn(
|
|
481
|
-
"min-w-0 flex-1 break-all font-mono text-[11px] leading-snug",
|
|
482
|
-
valueToneClass(row.kind),
|
|
483
|
-
)}
|
|
484
|
-
title={row.display}
|
|
485
|
-
>
|
|
486
|
-
{row.display}
|
|
487
|
-
</span>
|
|
488
|
-
</div>
|
|
489
|
-
<span className="mt-0.5 shrink-0 font-mono text-[9px] tracking-wide text-muted-foreground uppercase opacity-70">
|
|
490
|
-
{row.kind}
|
|
491
|
-
</span>
|
|
492
|
-
<div className="opacity-0 transition-opacity group-hover/field:opacity-100 group-focus-within/field:opacity-100">
|
|
493
|
-
<CopyIconButton
|
|
494
|
-
label={`Copy ${row.key}`}
|
|
495
|
-
text={fieldCopyText(row.value)}
|
|
496
|
-
dataSlot="trace-payload-copy-field"
|
|
497
|
-
bare
|
|
498
|
-
/>
|
|
499
|
-
</div>
|
|
500
|
-
</li>
|
|
604
|
+
<PayloadFieldRow key={row.key} row={row} depth={0} />
|
|
501
605
|
))}
|
|
502
606
|
</ul>
|
|
503
607
|
);
|
|
504
608
|
}
|
|
505
609
|
|
|
610
|
+
/**
|
|
611
|
+
* One payload field. Containers toggle a nested field list.
|
|
612
|
+
*
|
|
613
|
+
* @param props - Row + indent depth
|
|
614
|
+
*/
|
|
615
|
+
function PayloadFieldRow({
|
|
616
|
+
row,
|
|
617
|
+
depth,
|
|
618
|
+
}: {
|
|
619
|
+
readonly row: InputFieldRow;
|
|
620
|
+
readonly depth: number;
|
|
621
|
+
}): JSX.Element {
|
|
622
|
+
const expandable = row.children !== null;
|
|
623
|
+
const [open, setOpen] = useState(false);
|
|
624
|
+
|
|
625
|
+
return (
|
|
626
|
+
<li data-slot="trace-payload-field" data-depth={depth}>
|
|
627
|
+
<div
|
|
628
|
+
className={cn(EXPLORER_ROW_CLASS, "group/field items-start")}
|
|
629
|
+
style={depth > 0 ? { paddingLeft: `${10 + depth * 14}px` } : undefined}
|
|
630
|
+
>
|
|
631
|
+
{expandable ? (
|
|
632
|
+
<button
|
|
633
|
+
type="button"
|
|
634
|
+
className="mt-0.5 flex size-3.5 shrink-0 items-center justify-center text-muted-foreground"
|
|
635
|
+
aria-expanded={open}
|
|
636
|
+
aria-label={`${open ? "Collapse" : "Expand"} ${row.key}`}
|
|
637
|
+
data-slot="trace-payload-expand"
|
|
638
|
+
onClick={() => setOpen((next) => !next)}
|
|
639
|
+
>
|
|
640
|
+
<HugeiconsIcon
|
|
641
|
+
icon={ArrowDown01Icon}
|
|
642
|
+
className={cn(EXPLORER_CHEVRON_CLASS, !open && "-rotate-90")}
|
|
643
|
+
/>
|
|
644
|
+
</button>
|
|
645
|
+
) : (
|
|
646
|
+
<span className="mt-0.5 size-3.5 shrink-0" aria-hidden />
|
|
647
|
+
)}
|
|
648
|
+
<div className="flex min-w-0 flex-1 flex-col gap-0.5 sm:flex-row sm:items-baseline sm:gap-3">
|
|
649
|
+
<span className="w-[7.5rem] shrink-0 truncate font-mono text-[11px] font-medium text-sky-600 dark:text-sky-400">
|
|
650
|
+
{row.key}
|
|
651
|
+
</span>
|
|
652
|
+
<span
|
|
653
|
+
className={cn(
|
|
654
|
+
"min-w-0 flex-1 break-all font-mono text-[11px] leading-snug",
|
|
655
|
+
valueToneClass(row.kind),
|
|
656
|
+
)}
|
|
657
|
+
title={row.display}
|
|
658
|
+
>
|
|
659
|
+
{row.display}
|
|
660
|
+
</span>
|
|
661
|
+
</div>
|
|
662
|
+
<span className="mt-0.5 shrink-0 font-mono text-[9px] tracking-wide text-muted-foreground uppercase opacity-70">
|
|
663
|
+
{row.kind}
|
|
664
|
+
</span>
|
|
665
|
+
<div className="opacity-0 transition-opacity group-hover/field:opacity-100 group-focus-within/field:opacity-100">
|
|
666
|
+
<CopyIconButton
|
|
667
|
+
label={`Copy ${row.key}`}
|
|
668
|
+
text={fieldCopyText(row.value)}
|
|
669
|
+
dataSlot="trace-payload-copy-field"
|
|
670
|
+
bare
|
|
671
|
+
/>
|
|
672
|
+
</div>
|
|
673
|
+
</div>
|
|
674
|
+
{expandable && open ? (
|
|
675
|
+
<ul data-slot="trace-payload-children">
|
|
676
|
+
{row.children?.map((child) => (
|
|
677
|
+
<PayloadFieldRow key={child.key} row={child} depth={depth + 1} />
|
|
678
|
+
))}
|
|
679
|
+
</ul>
|
|
680
|
+
) : null}
|
|
681
|
+
</li>
|
|
682
|
+
);
|
|
683
|
+
}
|
|
684
|
+
|
|
506
685
|
function valueToneClass(kind: InputFieldKind): string {
|
|
507
686
|
switch (kind) {
|
|
508
687
|
case "string":
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Scoped Traces pane (start side of the Flow split-view).
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { useEffect, useMemo, useState } from "react";
|
|
5
|
+
import { useEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { Alert02Icon, FilterHorizontalIcon, Menu01Icon } from "@hugeicons/core-free-icons";
|
|
7
7
|
import { HugeiconsIcon } from "@hugeicons/react";
|
|
8
8
|
import type { Manifest } from "../../../../../../manifest/types.ts";
|
|
@@ -100,6 +100,11 @@ export function TracesPane({
|
|
|
100
100
|
return filterRunsByGraph(base, graphFilter, manifest);
|
|
101
101
|
}, [runs, filters, graphFilter, manifest]);
|
|
102
102
|
|
|
103
|
+
const navigationRuns = useMemo(() => {
|
|
104
|
+
if (!selectedRunId) return visible;
|
|
105
|
+
return visible.some((run) => run.id === selectedRunId) ? visible : runs;
|
|
106
|
+
}, [visible, runs, selectedRunId]);
|
|
107
|
+
|
|
103
108
|
const selectedRun = useMemo(
|
|
104
109
|
() =>
|
|
105
110
|
selectedRunProp !== undefined
|
|
@@ -123,6 +128,13 @@ export function TracesPane({
|
|
|
123
128
|
setFilters((prev) => ({ ...prev, advanced }));
|
|
124
129
|
};
|
|
125
130
|
|
|
131
|
+
const listRef = useRef<HTMLDivElement>(null);
|
|
132
|
+
useEffect(() => {
|
|
133
|
+
if (!selectedRunId || !listRef.current) return;
|
|
134
|
+
const row = listRef.current.querySelector(`[data-run-id="${CSS.escape(selectedRunId)}"]`);
|
|
135
|
+
if (row instanceof HTMLElement) row.scrollIntoView({ block: "nearest" });
|
|
136
|
+
}, [selectedRunId]);
|
|
137
|
+
|
|
126
138
|
return (
|
|
127
139
|
<div className="flex h-full min-h-0 flex-col overflow-hidden" data-slot="traces-pane">
|
|
128
140
|
<div className="shrink-0 border-b border-border/60">
|
|
@@ -249,7 +261,7 @@ export function TracesPane({
|
|
|
249
261
|
</AgentDisclosure>
|
|
250
262
|
) : null}
|
|
251
263
|
|
|
252
|
-
<div className="flex min-h-0 flex-1 flex-col overflow-y-auto">
|
|
264
|
+
<div ref={listRef} className="flex min-h-0 flex-1 flex-col overflow-y-auto">
|
|
253
265
|
{runs.length === 0 ? (
|
|
254
266
|
<Empty className="border-none">
|
|
255
267
|
<EmptyHeader>
|
|
@@ -290,6 +302,8 @@ export function TracesPane({
|
|
|
290
302
|
onFocusEffectChange={onFocusEffectChange}
|
|
291
303
|
playbackKey={playbackKey}
|
|
292
304
|
onReplayStart={onReplayStart}
|
|
305
|
+
navigationRuns={navigationRuns}
|
|
306
|
+
onSelectRun={(id) => onSelect(id)}
|
|
293
307
|
/>
|
|
294
308
|
</div>
|
|
295
309
|
);
|