causal-inspector 0.1.2 → 0.1.4
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/engines/query.js +21 -9
- package/dist/engines/url.js +8 -1
- package/dist/events.d.ts +7 -2
- package/dist/panes/TimelinePane.js +8 -68
- package/dist/queries.d.ts +1 -1
- package/dist/queries.js +11 -8
- package/dist/reducer.js +14 -4
- package/dist/state.d.ts +1 -0
- package/dist/state.js +1 -0
- package/dist/types.d.ts +4 -0
- package/package.json +1 -1
package/dist/engines/query.js
CHANGED
|
@@ -119,12 +119,24 @@ export const createQueryEngine = (transport) => {
|
|
|
119
119
|
console.error("[causal-inspector] fetch logs failed:", e);
|
|
120
120
|
}
|
|
121
121
|
};
|
|
122
|
-
|
|
122
|
+
let correlationCursor = null;
|
|
123
|
+
const fetchCorrelations = async (opts) => {
|
|
124
|
+
const append = opts?.append ?? false;
|
|
125
|
+
const cursor = append ? correlationCursor : undefined;
|
|
123
126
|
try {
|
|
124
|
-
const data = await transport.query(INSPECTOR_CORRELATIONS, {
|
|
127
|
+
const data = await transport.query(INSPECTOR_CORRELATIONS, {
|
|
128
|
+
search: opts?.search || undefined,
|
|
129
|
+
limit: 50,
|
|
130
|
+
cursor: cursor || undefined,
|
|
131
|
+
});
|
|
132
|
+
correlationCursor = data.inspectorCorrelations.nextCursor;
|
|
125
133
|
dispatch({
|
|
126
134
|
type: "events/correlations_loaded",
|
|
127
|
-
payload:
|
|
135
|
+
payload: {
|
|
136
|
+
correlations: data.inspectorCorrelations.correlations,
|
|
137
|
+
hasMore: data.inspectorCorrelations.nextCursor != null,
|
|
138
|
+
append,
|
|
139
|
+
},
|
|
128
140
|
});
|
|
129
141
|
}
|
|
130
142
|
catch (e) {
|
|
@@ -214,16 +226,16 @@ export const createQueryEngine = (transport) => {
|
|
|
214
226
|
fetchCausalTree(event.payload.seq);
|
|
215
227
|
break;
|
|
216
228
|
case "ui/filter_changed":
|
|
217
|
-
dispatch({
|
|
218
|
-
type: "events/page_loaded",
|
|
219
|
-
payload: { events: [], hasMore: true },
|
|
220
|
-
});
|
|
221
229
|
fetchEvents();
|
|
222
230
|
break;
|
|
231
|
+
case "ui/load_more_correlations_requested":
|
|
232
|
+
fetchCorrelations({ append: true });
|
|
233
|
+
break;
|
|
223
234
|
case "ui/correlations_requested":
|
|
224
|
-
|
|
235
|
+
correlationCursor = null;
|
|
236
|
+
fetchCorrelations({ search: event.payload.search });
|
|
225
237
|
stopCorrelationPolling();
|
|
226
|
-
correlationPollTimer = setInterval(() => fetchCorrelations(event.payload.search), 5000);
|
|
238
|
+
correlationPollTimer = setInterval(() => fetchCorrelations({ search: event.payload.search }), 5000);
|
|
227
239
|
break;
|
|
228
240
|
case "ui/aggregate_lifecycle_requested":
|
|
229
241
|
fetchAggregateLifecycle(event.payload.aggregateKey);
|
package/dist/engines/url.js
CHANGED
|
@@ -18,7 +18,7 @@ function buildSearch(correlationId, handler) {
|
|
|
18
18
|
else
|
|
19
19
|
params.delete("handler");
|
|
20
20
|
const search = params.toString();
|
|
21
|
-
return search ?
|
|
21
|
+
return search ? `${window.location.pathname}?${search}` : window.location.pathname;
|
|
22
22
|
}
|
|
23
23
|
/**
|
|
24
24
|
* URL engine — keeps the browser URL in sync with navigation state.
|
|
@@ -51,6 +51,13 @@ export const createUrlEngine = (dispatch, _getState) => {
|
|
|
51
51
|
case "ui/flow_closed":
|
|
52
52
|
window.history.pushState(null, "", buildSearch(null, null));
|
|
53
53
|
break;
|
|
54
|
+
case "ui/filter_changed": {
|
|
55
|
+
const payload = event.payload;
|
|
56
|
+
if (payload.correlationId !== undefined) {
|
|
57
|
+
window.history.pushState(null, "", buildSearch(payload.correlationId, null));
|
|
58
|
+
}
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
54
61
|
case "ui/handler_selected":
|
|
55
62
|
// Replace rather than push — handler changes within a flow are fine as one history entry
|
|
56
63
|
window.history.replaceState(null, "", buildSearch(new URLSearchParams(window.location.search).get("correlation"), event.payload.reactorId));
|
package/dist/events.d.ts
CHANGED
|
@@ -31,7 +31,11 @@ type OutcomesLoaded = BaseEvent<"events/outcomes_loaded", {
|
|
|
31
31
|
correlationId: string;
|
|
32
32
|
outcomes: ReactorOutcome[];
|
|
33
33
|
}>;
|
|
34
|
-
type CorrelationsLoaded = BaseEvent<"events/correlations_loaded",
|
|
34
|
+
type CorrelationsLoaded = BaseEvent<"events/correlations_loaded", {
|
|
35
|
+
correlations: CorrelationSummary[];
|
|
36
|
+
hasMore: boolean;
|
|
37
|
+
append: boolean;
|
|
38
|
+
}>;
|
|
35
39
|
type ReactorDependenciesLoaded = BaseEvent<"events/reactor_dependencies_loaded", ReactorDependency[]>;
|
|
36
40
|
type AggregateKeysLoaded = BaseEvent<"events/aggregate_keys_loaded", string[]>;
|
|
37
41
|
type AggregateLifecycleLoaded = BaseEvent<"events/aggregate_lifecycle_loaded", {
|
|
@@ -69,9 +73,10 @@ type HandlerSelected = BaseEvent<"ui/handler_selected", {
|
|
|
69
73
|
type AggregateLifecycleRequested = BaseEvent<"ui/aggregate_lifecycle_requested", {
|
|
70
74
|
aggregateKey: string;
|
|
71
75
|
}>;
|
|
76
|
+
type LoadMoreCorrelationsRequested = BaseEvent<"ui/load_more_correlations_requested">;
|
|
72
77
|
type LocationChanged = BaseEvent<"location/changed", {
|
|
73
78
|
correlationId: string | null;
|
|
74
79
|
handler: string | null;
|
|
75
80
|
}>;
|
|
76
|
-
export type InspectorMachineEvent = EventsReceived | SubscriptionConnected | SubscriptionError | PageLoaded | CausalTreeLoaded | FlowLoaded | LogsLoaded | DescriptionsLoaded | DescriptionSnapshotsLoaded | AggregateTimelineLoaded | OutcomesLoaded | CorrelationsLoaded | EventSelected | EventDeselected | FlowOpened | FlowClosed | FlowNodeSelected | FilterChanged | LoadMoreRequested | LayoutChanged | ScrubberStartChanged | ScrubberEndChanged | ScrubberPlayToggled | ScrubberSpeedChanged | CorrelationsRequested | ReactorDependenciesLoaded | AggregateKeysLoaded | HandlerSelected | LocationChanged | AggregateLifecycleLoaded | AggregateLifecycleRequested;
|
|
81
|
+
export type InspectorMachineEvent = EventsReceived | SubscriptionConnected | SubscriptionError | PageLoaded | CausalTreeLoaded | FlowLoaded | LogsLoaded | DescriptionsLoaded | DescriptionSnapshotsLoaded | AggregateTimelineLoaded | OutcomesLoaded | CorrelationsLoaded | EventSelected | EventDeselected | FlowOpened | FlowClosed | FlowNodeSelected | FilterChanged | LoadMoreRequested | LayoutChanged | ScrubberStartChanged | ScrubberEndChanged | ScrubberPlayToggled | ScrubberSpeedChanged | CorrelationsRequested | ReactorDependenciesLoaded | AggregateKeysLoaded | HandlerSelected | LocationChanged | AggregateLifecycleLoaded | AggregateLifecycleRequested | LoadMoreCorrelationsRequested;
|
|
77
82
|
export {};
|
|
@@ -5,61 +5,20 @@ import { FilterBar } from "../components/FilterBar";
|
|
|
5
5
|
import { CopyablePayload } from "../components/CopyablePayload";
|
|
6
6
|
import { eventTextColor, eventBg } from "../theme";
|
|
7
7
|
import { formatTs, compactPayload, aggregateKey, inScrubberRange } from "../utils";
|
|
8
|
-
import { Search, ChevronRight
|
|
9
|
-
function EventRow({ event, isSelected, onClick, onFilterCorrelation, onFilterStream, onInvestigate,
|
|
8
|
+
import { Search, ChevronRight } from "lucide-react";
|
|
9
|
+
function EventRow({ event, isSelected, onClick, onFilterCorrelation, onFilterStream, onInvestigate, }) {
|
|
10
10
|
const [payloadOpen, setPayloadOpen] = useState(false);
|
|
11
11
|
return (_jsxs("div", { className: `group w-full text-left px-3 py-2 border-b border-border transition-all duration-150 ${isSelected
|
|
12
12
|
? "bg-indigo-500/15"
|
|
13
|
-
: "hover:bg-white/[0.02]"}`,
|
|
13
|
+
: "hover:bg-white/[0.02]"}`, children: [_jsx("div", { onClick: onClick, role: "button", tabIndex: 0, className: "w-full text-left cursor-pointer", children: _jsxs("div", { className: "flex items-center gap-2.5 min-w-0", children: [_jsx("span", { className: "text-[10px] font-mono text-muted-foreground/60 w-10 shrink-0 text-right tabular-nums", children: event.seq }), _jsx("span", { className: "text-[10px] text-muted-foreground/70 shrink-0 w-32 tabular-nums", children: formatTs(event.ts) }), event.correlationId && (_jsx("button", { onClick: (e) => { e.stopPropagation(); onFilterCorrelation(event.correlationId); }, className: "px-1.5 py-0.5 rounded-full text-[9px] font-mono bg-purple-500/8 text-purple-400/80 hover:bg-purple-500/15 hover:text-purple-400 shrink-0 transition-all border border-purple-500/10", title: `Filter by correlation ${event.correlationId}`, children: event.correlationId.slice(0, 8) })), event.aggregateType && event.aggregateId && (_jsxs("button", { onClick: (e) => { e.stopPropagation(); onFilterStream(aggregateKey(event)); }, className: "opacity-0 group-hover:opacity-100 px-1.5 py-0.5 rounded-full text-[9px] font-mono bg-teal-500/8 text-teal-400/80 hover:bg-teal-500/15 hover:text-teal-400 shrink-0 transition-all border border-teal-500/10", title: `Filter by stream ${event.aggregateType}:${event.aggregateId}`, children: [event.aggregateType, ":", event.aggregateId.slice(0, 8)] })), _jsx("span", { className: "text-xs font-mono shrink-0 px-1.5 py-0.5 rounded", style: {
|
|
14
14
|
color: eventTextColor(event.name),
|
|
15
15
|
background: eventBg(event.name),
|
|
16
16
|
}, children: event.name }), _jsxs("button", { onClick: (e) => { e.stopPropagation(); setPayloadOpen((v) => !v); }, className: "flex items-center gap-1 text-[10px] font-mono text-muted-foreground/60 hover:text-muted-foreground truncate text-left min-w-0 transition-colors", title: "Click to expand payload", children: [_jsx(ChevronRight, { size: 10, className: `shrink-0 transition-transform duration-150 ${payloadOpen ? "rotate-90" : ""}` }), _jsx("span", { className: "truncate", children: event.summary ?? compactPayload(event.payload) })] }), onInvestigate && (_jsx("button", { onClick: (e) => { e.stopPropagation(); onInvestigate(); }, className: "opacity-0 group-hover:opacity-100 transition-opacity duration-150 ml-auto p-1 rounded-md hover:bg-white/[0.05] shrink-0 text-muted-foreground", title: "Investigate", children: _jsx(Search, { size: 12 }) }))] }) }), payloadOpen && (_jsx(CopyablePayload, { payload: event.payload, className: "mt-2 ml-12 max-h-64" }))] }));
|
|
17
17
|
}
|
|
18
|
-
function groupEventsByCorrelation(events) {
|
|
19
|
-
const result = [];
|
|
20
|
-
let i = 0;
|
|
21
|
-
while (i < events.length) {
|
|
22
|
-
const event = events[i];
|
|
23
|
-
if (!event.correlationId) {
|
|
24
|
-
result.push(event);
|
|
25
|
-
i++;
|
|
26
|
-
continue;
|
|
27
|
-
}
|
|
28
|
-
// Collect consecutive events with the same correlationId
|
|
29
|
-
const cid = event.correlationId;
|
|
30
|
-
const groupEvents = [event];
|
|
31
|
-
let j = i + 1;
|
|
32
|
-
while (j < events.length && events[j].correlationId === cid) {
|
|
33
|
-
groupEvents.push(events[j]);
|
|
34
|
-
j++;
|
|
35
|
-
}
|
|
36
|
-
if (groupEvents.length === 1) {
|
|
37
|
-
// Single event — render flat
|
|
38
|
-
result.push(event);
|
|
39
|
-
}
|
|
40
|
-
else {
|
|
41
|
-
// Find the root event (no reactorId) or fall back to first
|
|
42
|
-
const rootIdx = groupEvents.findIndex((e) => !e.reactorId);
|
|
43
|
-
const root = rootIdx >= 0 ? groupEvents[rootIdx] : groupEvents[0];
|
|
44
|
-
const children = groupEvents.filter((e) => e !== root);
|
|
45
|
-
result.push({ correlationId: cid, root, children });
|
|
46
|
-
}
|
|
47
|
-
i = j;
|
|
48
|
-
}
|
|
49
|
-
return result;
|
|
50
|
-
}
|
|
51
|
-
function EventGroupRow({ group, selectedSeq, collapsed, onToggle, onSelect, onFilterCorrelation, onFilterStream, onInvestigate, }) {
|
|
52
|
-
return (_jsxs("div", { children: [_jsxs("div", { className: "relative", children: [_jsx("button", { onClick: onToggle, className: "absolute left-1 top-2.5 z-10 p-0.5 rounded hover:bg-white/[0.05] text-muted-foreground/60 hover:text-muted-foreground transition-colors", title: collapsed ? "Expand group" : "Collapse group", children: collapsed ? _jsx(ChevronRight, { size: 12 }) : _jsx(ChevronDown, { size: 12 }) }), _jsxs("div", { className: "relative", children: [_jsx(EventRow, { event: group.root, isSelected: group.root.seq === selectedSeq, onClick: () => onSelect(group.root), onFilterCorrelation: onFilterCorrelation, onFilterStream: onFilterStream, onInvestigate: onInvestigate ? () => onInvestigate(group.root) : undefined }), collapsed && (_jsxs("span", { className: "absolute right-3 top-2.5 text-[9px] font-mono px-1.5 py-0.5 rounded-full bg-white/[0.04] text-muted-foreground/60 border border-border", children: ["+", group.children.length] }))] })] }), !collapsed &&
|
|
53
|
-
group.children.map((child) => (_jsx(EventRow, { event: child, isSelected: child.seq === selectedSeq, onClick: () => onSelect(child), onFilterCorrelation: onFilterCorrelation, onFilterStream: onFilterStream, onInvestigate: onInvestigate ? () => onInvestigate(child) : undefined, indent: true }, child.seq)))] }));
|
|
54
|
-
}
|
|
55
18
|
function InfiniteScrollSentinel({ onVisible, loading }) {
|
|
56
19
|
const ref = useRef(null);
|
|
57
20
|
const onVisibleRef = useRef(onVisible);
|
|
58
21
|
onVisibleRef.current = onVisible;
|
|
59
|
-
// Re-create observer when loading finishes so it re-checks visibility.
|
|
60
|
-
// Without this, if loaded events collapse into one group row the sentinel
|
|
61
|
-
// stays visible but the observer never fires again (it only fires on
|
|
62
|
-
// enter/leave transitions).
|
|
63
22
|
useEffect(() => {
|
|
64
23
|
if (loading)
|
|
65
24
|
return;
|
|
@@ -74,31 +33,21 @@ function InfiniteScrollSentinel({ onVisible, loading }) {
|
|
|
74
33
|
return (_jsx("div", { ref: ref, className: "flex items-center justify-center py-4", children: loading && (_jsxs("div", { className: "flex items-center gap-2", children: [_jsx("div", { className: "w-1.5 h-1.5 rounded-full bg-indigo-500/50 animate-pulse" }), _jsx("span", { className: "text-[10px] text-muted-foreground/60", children: "Loading" })] })) }));
|
|
75
34
|
}
|
|
76
35
|
export function TimelinePane({ onInvestigate } = {}) {
|
|
77
|
-
const events = useSelector((s) =>
|
|
36
|
+
const events = useSelector((s) => {
|
|
37
|
+
const cid = s.filters.correlationId;
|
|
38
|
+
return cid ? s.events.filter((e) => e.correlationId === cid) : s.events;
|
|
39
|
+
});
|
|
78
40
|
const loading = useSelector((s) => s.loading);
|
|
79
41
|
const hasMore = useSelector((s) => s.hasMore);
|
|
80
42
|
const selectedSeq = useSelector((s) => s.selectedSeq);
|
|
81
43
|
const scrubberStart = useSelector((s) => s.scrubberStart);
|
|
82
44
|
const scrubberEnd = useSelector((s) => s.scrubberEnd);
|
|
83
45
|
const dispatch = useDispatch();
|
|
84
|
-
// Default collapsed — this set tracks which groups are *expanded*
|
|
85
|
-
const [expandedGroups, setExpandedGroups] = useState(() => new Set());
|
|
86
46
|
const displayedEvents = useMemo(() => {
|
|
87
47
|
if (scrubberStart == null && scrubberEnd == null)
|
|
88
48
|
return events;
|
|
89
49
|
return events.filter(e => inScrubberRange(e.seq, scrubberStart, scrubberEnd));
|
|
90
50
|
}, [events, scrubberStart, scrubberEnd]);
|
|
91
|
-
const grouped = useMemo(() => groupEventsByCorrelation(displayedEvents), [displayedEvents]);
|
|
92
|
-
const toggleGroup = useCallback((correlationId) => {
|
|
93
|
-
setExpandedGroups((prev) => {
|
|
94
|
-
const next = new Set(prev);
|
|
95
|
-
if (next.has(correlationId))
|
|
96
|
-
next.delete(correlationId);
|
|
97
|
-
else
|
|
98
|
-
next.add(correlationId);
|
|
99
|
-
return next;
|
|
100
|
-
});
|
|
101
|
-
}, []);
|
|
102
51
|
const handleSelect = useCallback((event) => {
|
|
103
52
|
dispatch({ type: "ui/event_selected", payload: { seq: event.seq } });
|
|
104
53
|
if (event.correlationId) {
|
|
@@ -114,14 +63,5 @@ export function TimelinePane({ onInvestigate } = {}) {
|
|
|
114
63
|
const handleLoadMore = useCallback(() => {
|
|
115
64
|
dispatch({ type: "ui/load_more_requested" });
|
|
116
65
|
}, [dispatch]);
|
|
117
|
-
return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsx(FilterBar, {}), loading && events.length === 0 ? (_jsx("div", { className: "animate-pulse p-1", children: Array.from({ length: 12 }).map((_, i) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2.5 border-b border-border", children: [_jsx("div", { className: "h-3 w-10 bg-white/[0.03] rounded shrink-0" }), _jsx("div", { className: "h-3 w-32 bg-white/[0.03] rounded shrink-0" }), _jsx("div", { className: "h-3 bg-white/[0.03] rounded flex-1", style: { maxWidth: `${150 + (i * 37) % 200}px` } })] }, i))) })) : events.length === 0 ? (_jsx("div", { className: "flex items-center justify-center h-32 text-sm text-muted-foreground/60", children: "No events found" })) : (_jsxs("div", { className: "flex-1 overflow-y-auto", children: [
|
|
118
|
-
if ("correlationId" in item && "root" in item) {
|
|
119
|
-
// EventGroup
|
|
120
|
-
const group = item;
|
|
121
|
-
return (_jsx(EventGroupRow, { group: group, selectedSeq: selectedSeq, collapsed: !expandedGroups.has(group.correlationId), onToggle: () => toggleGroup(group.correlationId), onSelect: handleSelect, onFilterCorrelation: handleFilterCorrelation, onFilterStream: handleFilterStream, onInvestigate: onInvestigate }, `group-${group.correlationId}-${group.root.seq}`));
|
|
122
|
-
}
|
|
123
|
-
// Single event
|
|
124
|
-
const event = item;
|
|
125
|
-
return (_jsx(EventRow, { event: event, isSelected: event.seq === selectedSeq, onClick: () => handleSelect(event), onFilterCorrelation: handleFilterCorrelation, onFilterStream: handleFilterStream, onInvestigate: onInvestigate ? () => onInvestigate(event) : undefined }, event.seq));
|
|
126
|
-
}), hasMore && (_jsx(InfiniteScrollSentinel, { onVisible: handleLoadMore, loading: loading }))] }))] }));
|
|
66
|
+
return (_jsxs("div", { className: "flex flex-col h-full", children: [_jsx(FilterBar, {}), loading && events.length === 0 ? (_jsx("div", { className: "animate-pulse p-1", children: Array.from({ length: 12 }).map((_, i) => (_jsxs("div", { className: "flex items-center gap-2 px-3 py-2.5 border-b border-border", children: [_jsx("div", { className: "h-3 w-10 bg-white/[0.03] rounded shrink-0" }), _jsx("div", { className: "h-3 w-32 bg-white/[0.03] rounded shrink-0" }), _jsx("div", { className: "h-3 bg-white/[0.03] rounded flex-1", style: { maxWidth: `${150 + (i * 37) % 200}px` } })] }, i))) })) : events.length === 0 ? (_jsx("div", { className: "flex items-center justify-center h-32 text-sm text-muted-foreground/60", children: "No events found" })) : (_jsxs("div", { className: "flex-1 overflow-y-auto", children: [displayedEvents.map((event) => (_jsx(EventRow, { event: event, isSelected: event.seq === selectedSeq, onClick: () => handleSelect(event), onFilterCorrelation: handleFilterCorrelation, onFilterStream: handleFilterStream, onInvestigate: onInvestigate ? () => onInvestigate(event) : undefined }, event.seq))), hasMore && (_jsx(InfiniteScrollSentinel, { onVisible: handleLoadMore, loading: loading }))] }))] }));
|
|
127
67
|
}
|
package/dist/queries.d.ts
CHANGED
|
@@ -11,5 +11,5 @@ export declare const INSPECTOR_AGGREGATE_TIMELINE = "\n query InspectorAggregat
|
|
|
11
11
|
export declare const INSPECTOR_REACTOR_DEPENDENCIES = "\n query InspectorReactorDependencies {\n inspectorReactorDependencies {\n reactorId\n inputEventTypes\n outputEventTypes\n }\n }\n";
|
|
12
12
|
export declare const INSPECTOR_AGGREGATE_KEYS = "\n query InspectorAggregateKeys {\n inspectorAggregateKeys\n }\n";
|
|
13
13
|
export declare const INSPECTOR_AGGREGATE_LIFECYCLE = "\n query InspectorAggregateLifecycle($aggregateKey: String!, $limit: Int) {\n inspectorAggregateLifecycle(aggregateKey: $aggregateKey, limit: $limit) {\n seq\n eventId\n eventType\n ts\n correlationId\n aggregateKey\n state\n }\n }\n";
|
|
14
|
-
export declare const INSPECTOR_CORRELATIONS = "\n query InspectorCorrelations($search: String, $limit: Int) {\n inspectorCorrelations(search: $search, limit: $limit) {\n correlationId\n
|
|
14
|
+
export declare const INSPECTOR_CORRELATIONS = "\n query InspectorCorrelations($search: String, $limit: Int, $cursor: String) {\n inspectorCorrelations(search: $search, limit: $limit, cursor: $cursor) {\n correlations {\n correlationId\n eventCount\n firstTs\n lastTs\n rootEventType\n hasErrors\n }\n nextCursor\n }\n }\n";
|
|
15
15
|
export declare const INSPECTOR_REACTOR_OUTCOMES = "\n query InspectorReactorOutcomes($correlationId: String!) {\n inspectorReactorOutcomes(correlationId: $correlationId) {\n reactorId\n status\n error\n attempts\n startedAt\n completedAt\n triggeringEventIds\n }\n }\n";
|
package/dist/queries.js
CHANGED
|
@@ -145,14 +145,17 @@ export const INSPECTOR_AGGREGATE_LIFECYCLE = `
|
|
|
145
145
|
}
|
|
146
146
|
`;
|
|
147
147
|
export const INSPECTOR_CORRELATIONS = `
|
|
148
|
-
query InspectorCorrelations($search: String, $limit: Int) {
|
|
149
|
-
inspectorCorrelations(search: $search, limit: $limit) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
148
|
+
query InspectorCorrelations($search: String, $limit: Int, $cursor: String) {
|
|
149
|
+
inspectorCorrelations(search: $search, limit: $limit, cursor: $cursor) {
|
|
150
|
+
correlations {
|
|
151
|
+
correlationId
|
|
152
|
+
eventCount
|
|
153
|
+
firstTs
|
|
154
|
+
lastTs
|
|
155
|
+
rootEventType
|
|
156
|
+
hasErrors
|
|
157
|
+
}
|
|
158
|
+
nextCursor
|
|
156
159
|
}
|
|
157
160
|
}
|
|
158
161
|
`;
|
package/dist/reducer.js
CHANGED
|
@@ -47,8 +47,6 @@ export const reducer = (draft, event) => {
|
|
|
47
47
|
// ── Subscription ──
|
|
48
48
|
case "events/received": {
|
|
49
49
|
const newEvents = event.payload;
|
|
50
|
-
// Filter subscription events against active filters so they don't
|
|
51
|
-
// pollute the view when the user has a search or correlation filter.
|
|
52
50
|
const filtered = newEvents.filter((e) => {
|
|
53
51
|
if (draft.filters.correlationId && e.correlationId !== draft.filters.correlationId) {
|
|
54
52
|
return false;
|
|
@@ -111,10 +109,18 @@ export const reducer = (draft, event) => {
|
|
|
111
109
|
draft.outcomes[correlationId] = outcomes;
|
|
112
110
|
break;
|
|
113
111
|
}
|
|
114
|
-
case "events/correlations_loaded":
|
|
115
|
-
|
|
112
|
+
case "events/correlations_loaded": {
|
|
113
|
+
const { correlations, hasMore, append } = event.payload;
|
|
114
|
+
if (append) {
|
|
115
|
+
draft.correlations.push(...correlations);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
draft.correlations = correlations;
|
|
119
|
+
}
|
|
120
|
+
draft.correlationsHasMore = hasMore;
|
|
116
121
|
draft.correlationsLoading = false;
|
|
117
122
|
break;
|
|
123
|
+
}
|
|
118
124
|
case "events/reactor_dependencies_loaded":
|
|
119
125
|
draft.reactorDependencies = event.payload;
|
|
120
126
|
break;
|
|
@@ -137,6 +143,7 @@ export const reducer = (draft, event) => {
|
|
|
137
143
|
break;
|
|
138
144
|
case "location/changed":
|
|
139
145
|
applyNavigation(draft, event.payload.correlationId, event.payload.handler);
|
|
146
|
+
draft.filters.correlationId = event.payload.correlationId;
|
|
140
147
|
break;
|
|
141
148
|
// ── UI ──
|
|
142
149
|
case "ui/event_selected":
|
|
@@ -181,5 +188,8 @@ export const reducer = (draft, event) => {
|
|
|
181
188
|
case "ui/correlations_requested":
|
|
182
189
|
draft.correlationsLoading = true;
|
|
183
190
|
break;
|
|
191
|
+
case "ui/load_more_correlations_requested":
|
|
192
|
+
draft.correlationsLoading = true;
|
|
193
|
+
break;
|
|
184
194
|
}
|
|
185
195
|
};
|
package/dist/state.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ export type InspectorState = {
|
|
|
24
24
|
outcomes: Record<string, ReactorOutcome[]>;
|
|
25
25
|
correlations: CorrelationSummary[];
|
|
26
26
|
correlationsLoading: boolean;
|
|
27
|
+
correlationsHasMore: boolean;
|
|
27
28
|
reactorDependencies: ReactorDependency[];
|
|
28
29
|
aggregateKeys: string[];
|
|
29
30
|
aggregateLifecycle: AggregateLifecycleEntry[];
|
package/dist/state.js
CHANGED
package/dist/types.d.ts
CHANGED
|
@@ -113,6 +113,10 @@ export type CorrelationSummary = {
|
|
|
113
113
|
rootEventType: string;
|
|
114
114
|
hasErrors: boolean;
|
|
115
115
|
};
|
|
116
|
+
export type CorrelationSummaryPage = {
|
|
117
|
+
correlations: CorrelationSummary[];
|
|
118
|
+
nextCursor: string | null;
|
|
119
|
+
};
|
|
116
120
|
export type FilterState = {
|
|
117
121
|
search: string;
|
|
118
122
|
correlationId: string | null;
|