causal-inspector 0.1.0 → 0.1.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.
@@ -3,6 +3,10 @@
3
3
  .causal-inspector {
4
4
  height: 100%;
5
5
  width: 100%;
6
+ overflow: hidden;
7
+ position: relative;
8
+ display: flex;
9
+ flex-direction: column;
6
10
  background: #0a0a0f;
7
11
  color: #e0e0f0;
8
12
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif;
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useMemo, useRef, useCallback, useEffect } from "react";
3
3
  import { Layout, Model, Actions, DockLocation, } from "flexlayout-react";
4
4
  import { createClient } from "graphql-ws";
@@ -13,6 +13,7 @@ import { LogsPane } from "./panes/LogsPane";
13
13
  import { AggregateTimelinePane } from "./panes/AggregateTimelinePane";
14
14
  import { WaterfallPane } from "./panes/WaterfallPane";
15
15
  import { CorrelationExplorerPane } from "./panes/CorrelationExplorerPane";
16
+ import { GlobalScrubber } from "./components/GlobalScrubber";
16
17
  import "./CausalInspector.css";
17
18
  // ── Transport ─────────────────────────────────────────────────
18
19
  function createTransport(endpoint, fetchOptions) {
@@ -244,7 +245,7 @@ function InspectorLayout() {
244
245
  setTimeout(() => document.addEventListener("mousedown", close), 0);
245
246
  }, children: _jsx(Plus, { size: 14 }) }, "add-pane"));
246
247
  }, [addTab]);
247
- return (_jsx("div", { style: { height: "100%", width: "100%" }, children: _jsx(Layout, { ref: layoutRef, model: modelRef.current, factory: factory, onModelChange: onModelChange, onRenderTabSet: onRenderTabSet }) }));
248
+ return (_jsxs(_Fragment, { children: [_jsx("div", { style: { flex: 1, minHeight: 0 }, children: _jsx(Layout, { ref: layoutRef, model: modelRef.current, factory: factory, onModelChange: onModelChange, onRenderTabSet: onRenderTabSet }) }), _jsx(GlobalScrubber, {})] }));
248
249
  }
249
250
  // ── CausalInspector (public API) ──────────────────────────────
250
251
  const savedLayout = loadSavedLayout();
@@ -7,13 +7,7 @@ export function FilterBar() {
7
7
  return (_jsxs("div", { className: "flex flex-wrap items-center gap-2 px-3 py-2 border-b border-border", style: { background: "rgba(15, 15, 20, 0.6)", backdropFilter: "blur(8px)" }, children: [_jsxs("div", { className: "relative flex items-center", children: [_jsx(Search, { size: 12, className: "absolute left-2.5 text-muted-foreground pointer-events-none" }), _jsx("input", { type: "text", placeholder: "search events...", value: filters.search, onChange: (e) => dispatch({
8
8
  type: "ui/filter_changed",
9
9
  payload: { search: e.target.value },
10
- }), className: "pl-7 pr-2 py-1.5 text-xs rounded-md bg-background/50 border border-border text-foreground placeholder:text-muted-foreground w-64 focus:outline-none focus:ring-1 focus:ring-indigo-500/40 focus:border-indigo-500/30 transition-all" })] }), _jsx("span", { className: "w-px h-4 bg-border" }), _jsx("label", { className: "text-[10px] text-muted-foreground uppercase tracking-wider", children: "From" }), _jsx("input", { type: "date", value: filters.from ?? "", onChange: (e) => dispatch({
11
- type: "ui/filter_changed",
12
- payload: { from: e.target.value || null },
13
- }), className: "px-2 py-1.5 text-xs rounded-md bg-background/50 border border-border text-foreground w-32 focus:outline-none focus:ring-1 focus:ring-indigo-500/40 focus:border-indigo-500/30 transition-all" }), _jsx("label", { className: "text-[10px] text-muted-foreground uppercase tracking-wider", children: "To" }), _jsx("input", { type: "date", value: filters.to ?? "", onChange: (e) => dispatch({
14
- type: "ui/filter_changed",
15
- payload: { to: e.target.value || null },
16
- }), className: "px-2 py-1.5 text-xs rounded-md bg-background/50 border border-border text-foreground w-32 focus:outline-none focus:ring-1 focus:ring-indigo-500/40 focus:border-indigo-500/30 transition-all" }), filters.correlationId && (_jsxs(_Fragment, { children: [_jsx("span", { className: "w-px h-4 bg-border" }), _jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-purple-500/10 border border-purple-500/20 text-purple-400 text-[10px] font-mono", children: [filters.correlationId.slice(0, 8), _jsx("button", { onClick: () => dispatch({
10
+ }), className: "pl-7 pr-2 py-1.5 text-xs rounded-md bg-background/50 border border-border text-foreground placeholder:text-muted-foreground w-64 focus:outline-none focus:ring-1 focus:ring-indigo-500/40 focus:border-indigo-500/30 transition-all" })] }), filters.correlationId && (_jsxs(_Fragment, { children: [_jsx("span", { className: "w-px h-4 bg-border" }), _jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-purple-500/10 border border-purple-500/20 text-purple-400 text-[10px] font-mono", children: [filters.correlationId.slice(0, 8), _jsx("button", { onClick: () => dispatch({
17
11
  type: "ui/filter_changed",
18
12
  payload: { correlationId: null },
19
13
  }), className: "hover:text-foreground transition-colors", children: _jsx(X, { size: 10 }) })] })] })), filters.aggregateKey && (_jsxs(_Fragment, { children: [_jsx("span", { className: "w-px h-4 bg-border" }), _jsxs("span", { className: "inline-flex items-center gap-1.5 px-2.5 py-1 rounded-full bg-teal-500/10 border border-teal-500/20 text-teal-400 text-[10px] font-mono", children: [filters.aggregateKey.split(":")[0], ":", filters.aggregateKey.split(":").slice(1).join(":").slice(0, 8), _jsx("button", { onClick: () => dispatch({
@@ -22,8 +22,6 @@ export const createQueryEngine = (transport) => {
22
22
  limit: 50,
23
23
  cursor,
24
24
  search: state.filters.search || undefined,
25
- from: state.filters.from || undefined,
26
- to: state.filters.to || undefined,
27
25
  correlationId: state.filters.correlationId || undefined,
28
26
  aggregateKey: state.filters.aggregateKey || undefined,
29
27
  });
@@ -1,8 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { useMemo, useCallback, useEffect, useRef, useState } from "react";
3
3
  import { useSelector, useDispatch } from "../machine";
4
4
  import { eventBg, eventTextColor } from "../theme";
5
5
  import { inScrubberRange } from "../utils";
6
+ import { X } from "lucide-react";
6
7
  function tokenizeJson(json) {
7
8
  const tokens = [];
8
9
  const re = /("(?:[^"\\]|\\.)*")\s*:|("(?:[^"\\]|\\.)*")|(-?\d+(?:\.\d+)?(?:[eE][+-]?\d+)?)|(\btrue\b|\bfalse\b)|(\bnull\b)|([{}[\]:,])/g;
@@ -147,8 +148,20 @@ export function AggregateTimelinePane() {
147
148
  const entries = useSelector((s) => correlationId ? s.aggregateTimeline[correlationId] ?? [] : []);
148
149
  const scrubberStart = useSelector((s) => s.scrubberStart);
149
150
  const scrubberEnd = useSelector((s) => s.scrubberEnd);
151
+ const logsFilter = useSelector((s) => s.logsFilter);
152
+ const flowData = useSelector((s) => s.flowData);
150
153
  const dispatch = useDispatch();
151
154
  const [diffMode, setDiffMode] = useState(false);
155
+ // Map eventId → reactorId for handler selection highlighting
156
+ const eventReactorMap = useMemo(() => {
157
+ const map = new Map();
158
+ for (const e of flowData) {
159
+ if (e.id && e.reactorId)
160
+ map.set(e.id, e.reactorId);
161
+ }
162
+ return map;
163
+ }, [flowData]);
164
+ const hasReactorFilter = logsFilter.reactorId != null;
152
165
  // Build a lookup: seq → { aggKey → state } for computing diffs
153
166
  const prevStateMap = useMemo(() => {
154
167
  const map = new Map();
@@ -200,16 +213,18 @@ export function AggregateTimelinePane() {
200
213
  cursor: "pointer",
201
214
  transition: "all 150ms",
202
215
  letterSpacing: "0.02em",
203
- }, children: "Diff" })] }), _jsx("div", { style: { flex: 1, overflow: "auto", padding: "8px 12px" }, children: entries.map((entry, entryIdx) => {
216
+ }, children: "Diff" }), hasReactorFilter && (_jsxs(_Fragment, { children: [_jsx("div", { style: { width: 1, height: 14, background: "rgba(255,255,255,0.06)", marginLeft: 4, marginRight: 4 } }), _jsx("span", { style: { fontSize: 10, color: "#818cf8", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }, children: logsFilter.reactorId }), _jsx("button", { onClick: () => dispatch({ type: "ui/flow_node_selected", payload: null }), style: { background: "none", border: "none", cursor: "pointer", color: "#70708a", padding: 2, borderRadius: 4, display: "flex", alignItems: "center" }, title: "Clear selection", children: _jsx(X, { size: 12 }) })] }))] }), _jsx("div", { style: { flex: 1, overflow: "auto", padding: "8px 12px" }, children: entries.map((entry, entryIdx) => {
204
217
  const isOutside = (scrubberStart != null || scrubberEnd != null) && !inScrubberRange(entry.seq, scrubberStart, scrubberEnd);
205
218
  const isCurrent = scrubberEnd === entry.seq;
206
219
  const prevAggs = prevStateMap.get(entry.seq);
220
+ const entryReactorId = entry.eventId ? eventReactorMap.get(entry.eventId) : null;
221
+ const isReactorMatch = !hasReactorFilter || entryReactorId === logsFilter.reactorId;
207
222
  return (_jsxs("div", { ref: isCurrent ? currentRowRef : undefined, onClick: () => handleRowClick(entry.seq), style: {
208
- opacity: isOutside ? 0.3 : 1,
223
+ opacity: isOutside ? 0.3 : !isReactorMatch ? 0.35 : 1,
209
224
  padding: "6px 8px",
210
225
  marginBottom: 4,
211
226
  borderRadius: 6,
212
- background: isCurrent ? "rgba(99,102,241,0.15)" : "transparent",
227
+ background: isCurrent ? "rgba(99,102,241,0.15)" : isReactorMatch && hasReactorFilter ? "rgba(99,102,241,0.06)" : "transparent",
213
228
  cursor: "pointer",
214
229
  transition: "opacity 150ms, background 150ms",
215
230
  }, children: [_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, marginBottom: 4 }, children: [_jsxs("div", { style: { fontSize: 10, fontWeight: 600, color: "#a1a1aa", minWidth: 40 }, children: ["#", entry.seq] }), _jsx("div", { style: {
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { useMemo, useCallback } from "react";
3
3
  import { useSelector, useDispatch } from "../machine";
4
4
  import { inScrubberRange } from "../utils";
5
+ import { X } from "lucide-react";
5
6
  // ---------------------------------------------------------------------------
6
7
  // Timing helpers
7
8
  // ---------------------------------------------------------------------------
@@ -99,104 +100,107 @@ export function WaterfallPane() {
99
100
  if (bars.length === 0) {
100
101
  return (_jsx("div", { style: { height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "#50506a", fontSize: 12, letterSpacing: "0.03em" }, children: "No reactor execution data for this correlation" }));
101
102
  }
102
- return (_jsxs("div", { style: { height: "100%", overflow: "auto", padding: `10px ${PADDING_X}px` }, children: [_jsxs("div", { style: { display: "flex", marginBottom: 6, marginLeft: LABEL_WIDTH, position: "relative", height: 16 }, children: [_jsx("span", { style: { fontSize: 9, color: "#40405a", letterSpacing: "0.04em" }, children: "0ms" }), _jsx("span", { style: { fontSize: 9, color: "#40405a", position: "absolute", right: 0, letterSpacing: "0.04em" }, children: formatDuration(rangeMs) }), scrubberMs != null && scrubberMs >= minMs && scrubberMs <= maxMs && (_jsx("div", { style: {
103
- position: "absolute",
104
- left: `${((scrubberMs - minMs) / rangeMs) * 100}%`,
105
- top: 0,
106
- bottom: -4,
107
- width: 1,
108
- background: "#6366f1",
109
- pointerEvents: "none",
110
- boxShadow: "0 0 4px rgba(99, 102, 241, 0.4)",
111
- } }))] }), bars.map((bar) => {
112
- const offsetPct = ((bar.startMs - minMs) / rangeMs) * 100;
113
- const widthPct = Math.max(((bar.endMs - bar.startMs) / rangeMs) * 100, 0.5);
114
- const colors = statusColor(bar.status);
115
- const duration = bar.endMs - bar.startMs;
116
- // Scrubber sync: dim bars whose triggering events are all outside range
117
- const isFuture = (scrubberStart != null || scrubberEnd != null) &&
118
- bar.triggeringEventIds.length > 0 &&
119
- bar.triggeringEventIds.every((eid) => {
120
- const seq = eventIdToSeq.get(eid);
121
- return seq != null && !inScrubberRange(seq, scrubberStart, scrubberEnd);
122
- });
123
- // Scrubber cursor position within this bar's track
124
- const cursorPct = scrubberMs != null && scrubberMs >= minMs && scrubberMs <= maxMs
125
- ? ((scrubberMs - minMs) / rangeMs) * 100
126
- : null;
127
- const isSelected = logsFilter.reactorId === bar.reactorId;
128
- return (_jsxs("div", { onClick: () => handleBarClick(bar), style: {
129
- display: "flex",
130
- alignItems: "center",
131
- height: ROW_HEIGHT,
132
- gap: 0,
133
- opacity: isFuture ? 0.25 : 1,
134
- transition: "opacity 200ms, background 150ms",
135
- cursor: "pointer",
136
- borderRadius: 6,
137
- background: isSelected ? "rgba(99, 102, 241, 0.15)" : "transparent",
138
- paddingLeft: 4,
139
- paddingRight: 4,
140
- }, children: [_jsx("div", { style: {
141
- width: LABEL_WIDTH,
142
- flexShrink: 0,
143
- fontSize: 11,
144
- color: "#c0c0d0",
145
- fontWeight: 500,
146
- overflow: "hidden",
147
- textOverflow: "ellipsis",
148
- whiteSpace: "nowrap",
149
- paddingRight: 10,
150
- letterSpacing: "0.01em",
151
- }, title: bar.reactorId, children: bar.reactorId }), _jsxs("div", { style: {
152
- flex: 1,
153
- position: "relative",
154
- height: 22,
155
- background: "rgba(255, 255, 255, 0.02)",
156
- borderRadius: 5,
157
- overflow: "hidden",
158
- }, children: [_jsx("div", { style: {
159
- position: "absolute",
160
- left: `${offsetPct}%`,
161
- width: `${widthPct}%`,
162
- minWidth: BAR_MIN_WIDTH,
163
- height: "100%",
164
- background: `linear-gradient(90deg, ${colors.bar}, ${colors.barEnd})`,
165
- borderRadius: 4,
166
- opacity: 0.8,
167
- display: "flex",
168
- alignItems: "center",
169
- paddingLeft: 5,
170
- paddingRight: 5,
171
- boxShadow: `0 1px 4px ${colors.bar}30`,
172
- }, title: `${bar.reactorId}: ${bar.status} (${formatDuration(duration)})${bar.attempts > 1 ? ` — ${bar.attempts} attempts` : ""}${bar.error ? `\nError: ${bar.error}` : ""}`, children: _jsx("span", { style: {
173
- fontSize: 9,
174
- fontWeight: 600,
175
- color: "#0a0a0f",
176
- whiteSpace: "nowrap",
177
- overflow: "hidden",
178
- textOverflow: "ellipsis",
179
- }, children: formatDuration(duration) }) }), cursorPct != null && (_jsx("div", { style: {
180
- position: "absolute",
181
- left: `${cursorPct}%`,
182
- top: 0,
183
- bottom: 0,
184
- width: 1,
185
- background: "#6366f1",
186
- pointerEvents: "none",
187
- boxShadow: "0 0 4px rgba(99, 102, 241, 0.3)",
188
- } }))] }), _jsxs("div", { style: {
189
- width: 80,
190
- flexShrink: 0,
103
+ const hasReactorFilter = logsFilter.reactorId != null;
104
+ return (_jsxs("div", { style: { height: "100%", display: "flex", flexDirection: "column" }, children: [hasReactorFilter && (_jsxs("div", { style: { display: "flex", alignItems: "center", gap: 6, padding: "5px 12px", borderBottom: "1px solid rgba(255,255,255,0.06)", flexShrink: 0, background: "rgba(15, 15, 20, 0.6)", backdropFilter: "blur(8px)" }, children: [_jsx("span", { style: { fontSize: 10, color: "#818cf8", fontFamily: "ui-monospace, SFMono-Regular, Menlo, monospace" }, children: logsFilter.reactorId }), _jsx("button", { onClick: () => {
105
+ dispatch({ type: "ui/flow_node_selected", payload: null });
106
+ }, style: { marginLeft: "auto", background: "none", border: "none", cursor: "pointer", color: "#70708a", padding: 2, borderRadius: 4, display: "flex", alignItems: "center" }, title: "Clear selection", children: _jsx(X, { size: 12 }) })] })), _jsxs("div", { style: { flex: 1, overflow: "auto", padding: `10px ${PADDING_X}px` }, children: [_jsxs("div", { style: { display: "flex", marginBottom: 6, marginLeft: LABEL_WIDTH, position: "relative", height: 16 }, children: [_jsx("span", { style: { fontSize: 9, color: "#40405a", letterSpacing: "0.04em" }, children: "0ms" }), _jsx("span", { style: { fontSize: 9, color: "#40405a", position: "absolute", right: 0, letterSpacing: "0.04em" }, children: formatDuration(rangeMs) }), scrubberMs != null && scrubberMs >= minMs && scrubberMs <= maxMs && (_jsx("div", { style: {
107
+ position: "absolute",
108
+ left: `${((scrubberMs - minMs) / rangeMs) * 100}%`,
109
+ top: 0,
110
+ bottom: -4,
111
+ width: 1,
112
+ background: "#6366f1",
113
+ pointerEvents: "none",
114
+ boxShadow: "0 0 4px rgba(99, 102, 241, 0.4)",
115
+ } }))] }), bars.map((bar) => {
116
+ const offsetPct = ((bar.startMs - minMs) / rangeMs) * 100;
117
+ const widthPct = Math.max(((bar.endMs - bar.startMs) / rangeMs) * 100, 0.5);
118
+ const colors = statusColor(bar.status);
119
+ const duration = bar.endMs - bar.startMs;
120
+ // Scrubber sync: dim bars whose triggering events are all outside range
121
+ const isFuture = (scrubberStart != null || scrubberEnd != null) &&
122
+ bar.triggeringEventIds.length > 0 &&
123
+ bar.triggeringEventIds.every((eid) => {
124
+ const seq = eventIdToSeq.get(eid);
125
+ return seq != null && !inScrubberRange(seq, scrubberStart, scrubberEnd);
126
+ });
127
+ // Scrubber cursor position within this bar's track
128
+ const cursorPct = scrubberMs != null && scrubberMs >= minMs && scrubberMs <= maxMs
129
+ ? ((scrubberMs - minMs) / rangeMs) * 100
130
+ : null;
131
+ const isSelected = logsFilter.reactorId === bar.reactorId;
132
+ return (_jsxs("div", { onClick: () => handleBarClick(bar), style: {
191
133
  display: "flex",
192
134
  alignItems: "center",
193
- gap: 4,
194
- paddingLeft: 10,
195
- }, children: [_jsx("span", { style: {
196
- fontSize: 10,
135
+ height: ROW_HEIGHT,
136
+ gap: 0,
137
+ opacity: isFuture ? 0.25 : (hasReactorFilter && !isSelected) ? 0.35 : 1,
138
+ transition: "opacity 200ms, background 150ms",
139
+ cursor: "pointer",
140
+ borderRadius: 6,
141
+ background: isSelected ? "rgba(99, 102, 241, 0.15)" : "transparent",
142
+ paddingLeft: 4,
143
+ paddingRight: 4,
144
+ }, children: [_jsx("div", { style: {
145
+ width: LABEL_WIDTH,
146
+ flexShrink: 0,
147
+ fontSize: 11,
148
+ color: "#c0c0d0",
197
149
  fontWeight: 500,
198
- color: colors.text,
199
- opacity: 0.8,
200
- }, children: bar.status }), bar.attempts > 1 && (_jsxs("span", { style: { fontSize: 9, color: "#50506a" }, children: ["x", bar.attempts] }))] })] }, bar.reactorId));
201
- }), _jsxs("div", { style: { marginTop: 10, fontSize: 10, color: "#40405a", marginLeft: LABEL_WIDTH, letterSpacing: "0.03em" }, children: ["Total wall time: ", formatDuration(rangeMs)] })] }));
150
+ overflow: "hidden",
151
+ textOverflow: "ellipsis",
152
+ whiteSpace: "nowrap",
153
+ paddingRight: 10,
154
+ letterSpacing: "0.01em",
155
+ }, title: bar.reactorId, children: bar.reactorId }), _jsxs("div", { style: {
156
+ flex: 1,
157
+ position: "relative",
158
+ height: 22,
159
+ background: "rgba(255, 255, 255, 0.02)",
160
+ borderRadius: 5,
161
+ overflow: "hidden",
162
+ }, children: [_jsx("div", { style: {
163
+ position: "absolute",
164
+ left: `${offsetPct}%`,
165
+ width: `${widthPct}%`,
166
+ minWidth: BAR_MIN_WIDTH,
167
+ height: "100%",
168
+ background: `linear-gradient(90deg, ${colors.bar}, ${colors.barEnd})`,
169
+ borderRadius: 4,
170
+ opacity: 0.8,
171
+ display: "flex",
172
+ alignItems: "center",
173
+ paddingLeft: 5,
174
+ paddingRight: 5,
175
+ boxShadow: `0 1px 4px ${colors.bar}30`,
176
+ }, title: `${bar.reactorId}: ${bar.status} (${formatDuration(duration)})${bar.attempts > 1 ? ` — ${bar.attempts} attempts` : ""}${bar.error ? `\nError: ${bar.error}` : ""}`, children: _jsx("span", { style: {
177
+ fontSize: 9,
178
+ fontWeight: 600,
179
+ color: "#0a0a0f",
180
+ whiteSpace: "nowrap",
181
+ overflow: "hidden",
182
+ textOverflow: "ellipsis",
183
+ }, children: formatDuration(duration) }) }), cursorPct != null && (_jsx("div", { style: {
184
+ position: "absolute",
185
+ left: `${cursorPct}%`,
186
+ top: 0,
187
+ bottom: 0,
188
+ width: 1,
189
+ background: "#6366f1",
190
+ pointerEvents: "none",
191
+ boxShadow: "0 0 4px rgba(99, 102, 241, 0.3)",
192
+ } }))] }), _jsxs("div", { style: {
193
+ width: 80,
194
+ flexShrink: 0,
195
+ display: "flex",
196
+ alignItems: "center",
197
+ gap: 4,
198
+ paddingLeft: 10,
199
+ }, children: [_jsx("span", { style: {
200
+ fontSize: 10,
201
+ fontWeight: 500,
202
+ color: colors.text,
203
+ opacity: 0.8,
204
+ }, children: bar.status }), bar.attempts > 1 && (_jsxs("span", { style: { fontSize: 9, color: "#50506a" }, children: ["x", bar.attempts] }))] })] }, bar.reactorId));
205
+ }), _jsxs("div", { style: { marginTop: 10, fontSize: 10, color: "#40405a", marginLeft: LABEL_WIDTH, letterSpacing: "0.03em" }, children: ["Total wall time: ", formatDuration(rangeMs)] })] })] }));
202
206
  }
package/dist/queries.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  /** GraphQL query and subscription documents for the causal inspector API. */
2
2
  export declare const EVENTS_SUBSCRIPTION = "\n subscription Events($lastSeq: Int) {\n inspectorEventAdded(lastSeq: $lastSeq) {\n \n seq\n ts\n type\n name\n id\n parentId\n correlationId\n reactorId\n aggregateType\n aggregateId\n streamVersion\n summary\n payload\n\n }\n }\n";
3
- export declare const INSPECTOR_EVENTS = "\n query InspectorEvents(\n $limit: Int!\n $cursor: Int\n $search: String\n $from: DateTime\n $to: DateTime\n $correlationId: String\n $aggregateKey: String\n ) {\n inspectorEvents(\n limit: $limit\n cursor: $cursor\n search: $search\n from: $from\n to: $to\n correlationId: $correlationId\n aggregateKey: $aggregateKey\n ) {\n events {\n \n seq\n ts\n type\n name\n id\n parentId\n correlationId\n reactorId\n aggregateType\n aggregateId\n streamVersion\n summary\n payload\n\n }\n nextCursor\n }\n }\n";
3
+ export declare const INSPECTOR_EVENTS = "\n query InspectorEvents(\n $limit: Int!\n $cursor: Int\n $search: String\n $correlationId: String\n $aggregateKey: String\n ) {\n inspectorEvents(\n limit: $limit\n cursor: $cursor\n search: $search\n correlationId: $correlationId\n aggregateKey: $aggregateKey\n ) {\n events {\n \n seq\n ts\n type\n name\n id\n parentId\n correlationId\n reactorId\n aggregateType\n aggregateId\n streamVersion\n summary\n payload\n\n }\n nextCursor\n }\n }\n";
4
4
  export declare const INSPECTOR_CAUSAL_TREE = "\n query InspectorCausalTree($seq: Int!) {\n inspectorCausalTree(seq: $seq) {\n events {\n \n seq\n ts\n type\n name\n id\n parentId\n correlationId\n reactorId\n aggregateType\n aggregateId\n streamVersion\n summary\n payload\n\n }\n rootSeq\n }\n }\n";
5
5
  export declare const INSPECTOR_CAUSAL_FLOW = "\n query InspectorCausalFlow($correlationId: String!) {\n inspectorCausalFlow(correlationId: $correlationId) {\n events {\n \n seq\n ts\n type\n name\n id\n parentId\n correlationId\n reactorId\n aggregateType\n aggregateId\n streamVersion\n summary\n payload\n\n }\n }\n }\n";
6
6
  export declare const INSPECTOR_REACTOR_LOGS = "\n query InspectorReactorLogs($eventId: String!, $reactorId: String!) {\n inspectorReactorLogs(eventId: $eventId, reactorId: $reactorId) {\n eventId\n reactorId\n level\n message\n data\n loggedAt\n }\n }\n";
package/dist/queries.js CHANGED
@@ -26,8 +26,6 @@ export const INSPECTOR_EVENTS = `
26
26
  $limit: Int!
27
27
  $cursor: Int
28
28
  $search: String
29
- $from: DateTime
30
- $to: DateTime
31
29
  $correlationId: String
32
30
  $aggregateKey: String
33
31
  ) {
@@ -35,8 +33,6 @@ export const INSPECTOR_EVENTS = `
35
33
  limit: $limit
36
34
  cursor: $cursor
37
35
  search: $search
38
- from: $from
39
- to: $to
40
36
  correlationId: $correlationId
41
37
  aggregateKey: $aggregateKey
42
38
  ) {
package/dist/reducer.js CHANGED
@@ -148,6 +148,14 @@ export const reducer = (draft, event) => {
148
148
  break;
149
149
  case "ui/flow_node_selected":
150
150
  draft.flowSelection = event.payload;
151
+ // Clear reactor filter when deselecting a node
152
+ if (event.payload == null && draft.logsFilter.reactorId != null) {
153
+ draft.logsFilter = {
154
+ scope: "correlation",
155
+ reactorId: null,
156
+ correlationId: draft.flowCorrelationId,
157
+ };
158
+ }
151
159
  break;
152
160
  case "ui/filter_changed":
153
161
  Object.assign(draft.filters, event.payload);
package/dist/state.js CHANGED
@@ -13,8 +13,6 @@ export const initialState = {
13
13
  causalTree: null,
14
14
  filters: {
15
15
  search: "",
16
- from: null,
17
- to: null,
18
16
  correlationId: null,
19
17
  aggregateKey: null,
20
18
  },
package/dist/types.d.ts CHANGED
@@ -115,8 +115,6 @@ export type CorrelationSummary = {
115
115
  };
116
116
  export type FilterState = {
117
117
  search: string;
118
- from: string | null;
119
- to: string | null;
120
118
  correlationId: string | null;
121
119
  aggregateKey: string | null;
122
120
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "causal-inspector",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "type": "module",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",