@industry-theme/principal-view-panels 0.1.47 → 0.1.48
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/panels.bundle.js
CHANGED
|
@@ -16,6 +16,7 @@ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "sy
|
|
|
16
16
|
import require$$0, { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
17
17
|
import React2, { createContext, useContext, forwardRef, createElement, useState, useCallback, useRef, useEffect } from "react";
|
|
18
18
|
import require$$2 from "react-dom";
|
|
19
|
+
import { trace, SpanStatusCode } from "@opentelemetry/api";
|
|
19
20
|
var ThemeContext;
|
|
20
21
|
var getThemeContext = () => {
|
|
21
22
|
if (typeof window !== "undefined") {
|
|
@@ -5662,6 +5663,623 @@ ${description}` : `# ${name}`;
|
|
|
5662
5663
|
return canvas;
|
|
5663
5664
|
}
|
|
5664
5665
|
}
|
|
5666
|
+
class EventValidationError extends Error {
|
|
5667
|
+
constructor(eventName, nodeId, errors) {
|
|
5668
|
+
super(`Event validation failed for '${eventName}' on node '${nodeId}':
|
|
5669
|
+
${errors.join("\n")}`);
|
|
5670
|
+
this.eventName = eventName;
|
|
5671
|
+
this.nodeId = nodeId;
|
|
5672
|
+
this.errors = errors;
|
|
5673
|
+
this.name = "EventValidationError";
|
|
5674
|
+
}
|
|
5675
|
+
}
|
|
5676
|
+
class EventValidator {
|
|
5677
|
+
constructor(canvas) {
|
|
5678
|
+
this.eventSchemas = /* @__PURE__ */ new Map();
|
|
5679
|
+
this.indexEventSchemas(canvas);
|
|
5680
|
+
}
|
|
5681
|
+
/**
|
|
5682
|
+
* Index all event schemas from canvas nodes
|
|
5683
|
+
*/
|
|
5684
|
+
indexEventSchemas(canvas) {
|
|
5685
|
+
var _a;
|
|
5686
|
+
if (!canvas.nodes)
|
|
5687
|
+
return;
|
|
5688
|
+
for (const node of canvas.nodes) {
|
|
5689
|
+
if ((_a = node.pv) == null ? void 0 : _a.events) {
|
|
5690
|
+
this.eventSchemas.set(node.id, node.pv.events);
|
|
5691
|
+
}
|
|
5692
|
+
}
|
|
5693
|
+
}
|
|
5694
|
+
/**
|
|
5695
|
+
* Validate an event against the schema for a specific node
|
|
5696
|
+
*/
|
|
5697
|
+
validate(nodeId, eventName, attributes) {
|
|
5698
|
+
const errors = [];
|
|
5699
|
+
const nodeSchema = this.eventSchemas.get(nodeId);
|
|
5700
|
+
if (!nodeSchema) {
|
|
5701
|
+
return { valid: true, errors: [] };
|
|
5702
|
+
}
|
|
5703
|
+
const eventSchema = nodeSchema[eventName];
|
|
5704
|
+
if (!eventSchema) {
|
|
5705
|
+
errors.push(`Event '${eventName}' is not defined in schema for node '${nodeId}'`);
|
|
5706
|
+
return { valid: false, errors };
|
|
5707
|
+
}
|
|
5708
|
+
for (const [fieldName, fieldSchema] of Object.entries(eventSchema.attributes)) {
|
|
5709
|
+
const value = attributes[fieldName];
|
|
5710
|
+
if (fieldSchema.required && value === void 0) {
|
|
5711
|
+
errors.push(`Required field '${fieldName}' is missing`);
|
|
5712
|
+
continue;
|
|
5713
|
+
}
|
|
5714
|
+
if (value === void 0) {
|
|
5715
|
+
continue;
|
|
5716
|
+
}
|
|
5717
|
+
const actualType = this.getValueType(value);
|
|
5718
|
+
if (actualType !== fieldSchema.type) {
|
|
5719
|
+
errors.push(`Field '${fieldName}' has type '${actualType}' but schema expects '${fieldSchema.type}'`);
|
|
5720
|
+
}
|
|
5721
|
+
}
|
|
5722
|
+
const schemaFields = new Set(Object.keys(eventSchema.attributes));
|
|
5723
|
+
for (const fieldName of Object.keys(attributes)) {
|
|
5724
|
+
if (fieldName.startsWith("code.") || fieldName === "description") {
|
|
5725
|
+
continue;
|
|
5726
|
+
}
|
|
5727
|
+
if (!schemaFields.has(fieldName)) ;
|
|
5728
|
+
}
|
|
5729
|
+
return {
|
|
5730
|
+
valid: errors.length === 0,
|
|
5731
|
+
errors
|
|
5732
|
+
};
|
|
5733
|
+
}
|
|
5734
|
+
/**
|
|
5735
|
+
* Get the type of a value
|
|
5736
|
+
*/
|
|
5737
|
+
getValueType(value) {
|
|
5738
|
+
if (Array.isArray(value))
|
|
5739
|
+
return "array";
|
|
5740
|
+
if (value === null)
|
|
5741
|
+
return "object";
|
|
5742
|
+
return typeof value;
|
|
5743
|
+
}
|
|
5744
|
+
/**
|
|
5745
|
+
* Get all event schemas for a node
|
|
5746
|
+
*/
|
|
5747
|
+
getNodeSchema(nodeId) {
|
|
5748
|
+
return this.eventSchemas.get(nodeId);
|
|
5749
|
+
}
|
|
5750
|
+
/**
|
|
5751
|
+
* Get all defined event names for a node
|
|
5752
|
+
*/
|
|
5753
|
+
getNodeEventNames(nodeId) {
|
|
5754
|
+
const schema2 = this.eventSchemas.get(nodeId);
|
|
5755
|
+
return schema2 ? Object.keys(schema2) : [];
|
|
5756
|
+
}
|
|
5757
|
+
/**
|
|
5758
|
+
* Check if a node has event schema defined
|
|
5759
|
+
*/
|
|
5760
|
+
hasSchema(nodeId) {
|
|
5761
|
+
return this.eventSchemas.has(nodeId);
|
|
5762
|
+
}
|
|
5763
|
+
}
|
|
5764
|
+
function createValidatedEmitter(validator, nodeId, addEventFn, options = {}) {
|
|
5765
|
+
return (eventName, attributes) => {
|
|
5766
|
+
const result = validator.validate(nodeId, eventName, attributes);
|
|
5767
|
+
if (!result.valid) {
|
|
5768
|
+
if (options.strict !== false) {
|
|
5769
|
+
throw new EventValidationError(eventName, nodeId, result.errors);
|
|
5770
|
+
} else {
|
|
5771
|
+
console.warn(`Event validation warnings for '${eventName}' on node '${nodeId}':`, result.errors);
|
|
5772
|
+
}
|
|
5773
|
+
}
|
|
5774
|
+
addEventFn(eventName, attributes);
|
|
5775
|
+
};
|
|
5776
|
+
}
|
|
5777
|
+
class TypeScriptGenerator {
|
|
5778
|
+
constructor() {
|
|
5779
|
+
this.language = "typescript";
|
|
5780
|
+
}
|
|
5781
|
+
generate(canvas, options) {
|
|
5782
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
5783
|
+
const opts = {
|
|
5784
|
+
readonly: ((_a = options == null ? void 0 : options.style) == null ? void 0 : _a.readonly) ?? false,
|
|
5785
|
+
strictNullChecks: ((_b = options == null ? void 0 : options.style) == null ? void 0 : _b.strictNullChecks) ?? true,
|
|
5786
|
+
includeDocComments: ((_c = options == null ? void 0 : options.style) == null ? void 0 : _c.includeDocComments) ?? true,
|
|
5787
|
+
namespace: options == null ? void 0 : options.namespace
|
|
5788
|
+
};
|
|
5789
|
+
const lines = [];
|
|
5790
|
+
lines.push("/**");
|
|
5791
|
+
lines.push(` * Generated types from canvas: ${((_d = canvas.pv) == null ? void 0 : _d.name) || "Untitled"}`);
|
|
5792
|
+
lines.push(" *");
|
|
5793
|
+
lines.push(" * DO NOT EDIT MANUALLY - This file is auto-generated");
|
|
5794
|
+
lines.push(" * Generated by @principal-ai/principal-view-core");
|
|
5795
|
+
lines.push(" *");
|
|
5796
|
+
lines.push(` * Canvas: ${((_e = canvas.pv) == null ? void 0 : _e.description) || "No description"}`);
|
|
5797
|
+
lines.push(` * Version: ${((_f = canvas.pv) == null ? void 0 : _f.version) || "1.0.0"}`);
|
|
5798
|
+
lines.push(" */");
|
|
5799
|
+
lines.push("");
|
|
5800
|
+
if (opts.namespace) {
|
|
5801
|
+
lines.push(`export namespace ${opts.namespace} {`);
|
|
5802
|
+
}
|
|
5803
|
+
if (canvas.nodes) {
|
|
5804
|
+
for (const node of canvas.nodes) {
|
|
5805
|
+
if ((_g = node.pv) == null ? void 0 : _g.events) {
|
|
5806
|
+
lines.push(...this.generateNodeTypes(node.id, node.pv.events, opts));
|
|
5807
|
+
lines.push("");
|
|
5808
|
+
}
|
|
5809
|
+
}
|
|
5810
|
+
}
|
|
5811
|
+
lines.push(...this.generateEventNameUnion(canvas, opts));
|
|
5812
|
+
lines.push("");
|
|
5813
|
+
lines.push(...this.generateEmitterTypes(canvas, opts));
|
|
5814
|
+
if (opts.namespace) {
|
|
5815
|
+
lines.push("}");
|
|
5816
|
+
}
|
|
5817
|
+
const code = lines.join("\n");
|
|
5818
|
+
const filename = this.generateFilename(canvas);
|
|
5819
|
+
return {
|
|
5820
|
+
code,
|
|
5821
|
+
extension: "ts",
|
|
5822
|
+
filename
|
|
5823
|
+
};
|
|
5824
|
+
}
|
|
5825
|
+
generateNodeTypes(nodeId, events, opts) {
|
|
5826
|
+
const lines = [];
|
|
5827
|
+
const typeName = this.nodeIdToTypeName(nodeId);
|
|
5828
|
+
if (opts.includeDocComments) {
|
|
5829
|
+
lines.push(`/**`);
|
|
5830
|
+
lines.push(` * Event types for node: ${nodeId}`);
|
|
5831
|
+
lines.push(` */`);
|
|
5832
|
+
}
|
|
5833
|
+
lines.push(`export namespace ${typeName} {`);
|
|
5834
|
+
for (const [eventName, eventSchema] of Object.entries(events)) {
|
|
5835
|
+
lines.push(...this.generateEventInterface(eventName, eventSchema, opts));
|
|
5836
|
+
lines.push("");
|
|
5837
|
+
}
|
|
5838
|
+
const eventNames = Object.keys(events);
|
|
5839
|
+
const interfaceNames = eventNames.map((name) => this.eventNameToTypeName(name));
|
|
5840
|
+
lines.push(" /**");
|
|
5841
|
+
lines.push(` * Union of all event types for ${nodeId}`);
|
|
5842
|
+
lines.push(" */");
|
|
5843
|
+
lines.push(` export type Event = ${interfaceNames.join(" | ")};`);
|
|
5844
|
+
lines.push("");
|
|
5845
|
+
lines.push(" /**");
|
|
5846
|
+
lines.push(` * Literal union of event names for ${nodeId}`);
|
|
5847
|
+
lines.push(" */");
|
|
5848
|
+
lines.push(` export type EventName = ${eventNames.map((n) => `'${n}'`).join(" | ")};`);
|
|
5849
|
+
lines.push("}");
|
|
5850
|
+
return lines;
|
|
5851
|
+
}
|
|
5852
|
+
generateEventInterface(eventName, schema2, opts) {
|
|
5853
|
+
const lines = [];
|
|
5854
|
+
const interfaceName = this.eventNameToTypeName(eventName);
|
|
5855
|
+
const readonly = opts.readonly ? "readonly " : "";
|
|
5856
|
+
if (opts.includeDocComments) {
|
|
5857
|
+
lines.push(" /**");
|
|
5858
|
+
lines.push(` * ${schema2.description}`);
|
|
5859
|
+
lines.push(" */");
|
|
5860
|
+
}
|
|
5861
|
+
lines.push(` export interface ${interfaceName} {`);
|
|
5862
|
+
lines.push(` ${readonly}name: '${eventName}';`);
|
|
5863
|
+
lines.push(` ${readonly}attributes: {`);
|
|
5864
|
+
for (const [fieldName, fieldSchema] of Object.entries(schema2.attributes)) {
|
|
5865
|
+
const optional = !fieldSchema.required && opts.strictNullChecks ? "?" : "";
|
|
5866
|
+
const type2 = this.fieldTypeToTsType(fieldSchema);
|
|
5867
|
+
if (opts.includeDocComments && fieldSchema.description) {
|
|
5868
|
+
lines.push(` /** ${fieldSchema.description} */`);
|
|
5869
|
+
}
|
|
5870
|
+
lines.push(` ${readonly}'${fieldName}'${optional}: ${type2};`);
|
|
5871
|
+
}
|
|
5872
|
+
lines.push(" };");
|
|
5873
|
+
lines.push(" }");
|
|
5874
|
+
return lines;
|
|
5875
|
+
}
|
|
5876
|
+
generateEventNameUnion(canvas, opts) {
|
|
5877
|
+
var _a;
|
|
5878
|
+
const lines = [];
|
|
5879
|
+
const allEventNames = /* @__PURE__ */ new Set();
|
|
5880
|
+
if (canvas.nodes) {
|
|
5881
|
+
for (const node of canvas.nodes) {
|
|
5882
|
+
if ((_a = node.pv) == null ? void 0 : _a.events) {
|
|
5883
|
+
Object.keys(node.pv.events).forEach((name) => allEventNames.add(name));
|
|
5884
|
+
}
|
|
5885
|
+
}
|
|
5886
|
+
}
|
|
5887
|
+
if (allEventNames.size === 0) {
|
|
5888
|
+
return lines;
|
|
5889
|
+
}
|
|
5890
|
+
if (opts.includeDocComments) {
|
|
5891
|
+
lines.push("/**");
|
|
5892
|
+
lines.push(" * Union of all event names in the canvas");
|
|
5893
|
+
lines.push(" */");
|
|
5894
|
+
}
|
|
5895
|
+
lines.push(`export type AllEventNames = ${Array.from(allEventNames).map((n) => `'${n}'`).join(" | ")};`);
|
|
5896
|
+
return lines;
|
|
5897
|
+
}
|
|
5898
|
+
generateEmitterTypes(canvas, opts) {
|
|
5899
|
+
const lines = [];
|
|
5900
|
+
if (opts.includeDocComments) {
|
|
5901
|
+
lines.push("/**");
|
|
5902
|
+
lines.push(" * Type-safe event emitter for a specific node");
|
|
5903
|
+
lines.push(" *");
|
|
5904
|
+
lines.push(" * @example");
|
|
5905
|
+
lines.push(" * ```typescript");
|
|
5906
|
+
lines.push(" * const emit: NodeEmitter<GraphConverter.EventName, GraphConverter.Event> = ...");
|
|
5907
|
+
lines.push(" * emit('conversion.started', {");
|
|
5908
|
+
lines.push(" * name: 'conversion.started',");
|
|
5909
|
+
lines.push(" * attributes: { ... }");
|
|
5910
|
+
lines.push(" * });");
|
|
5911
|
+
lines.push(" * ```");
|
|
5912
|
+
lines.push(" */");
|
|
5913
|
+
}
|
|
5914
|
+
lines.push("export type NodeEmitter<");
|
|
5915
|
+
lines.push(" TEventName extends string,");
|
|
5916
|
+
lines.push(" TEvent extends { name: TEventName; attributes: Record<string, any> }");
|
|
5917
|
+
lines.push("> = (event: TEvent) => void;");
|
|
5918
|
+
lines.push("");
|
|
5919
|
+
if (opts.includeDocComments) {
|
|
5920
|
+
lines.push("/**");
|
|
5921
|
+
lines.push(" * Type-safe event emitter by event name");
|
|
5922
|
+
lines.push(" *");
|
|
5923
|
+
lines.push(" * @example");
|
|
5924
|
+
lines.push(" * ```typescript");
|
|
5925
|
+
lines.push(" * const emit: NodeEmitterByName<GraphConverter.Event> = ...");
|
|
5926
|
+
lines.push(" * emit('conversion.started', {");
|
|
5927
|
+
lines.push(" * 'config.nodeTypes': 2,");
|
|
5928
|
+
lines.push(" * 'config.edgeTypes': 1");
|
|
5929
|
+
lines.push(" * });");
|
|
5930
|
+
lines.push(" * ```");
|
|
5931
|
+
lines.push(" */");
|
|
5932
|
+
}
|
|
5933
|
+
lines.push("export type NodeEmitterByName<");
|
|
5934
|
+
lines.push(" TEvent extends { name: string; attributes: Record<string, any> }");
|
|
5935
|
+
lines.push("> = <TName extends TEvent['name']>(");
|
|
5936
|
+
lines.push(" eventName: TName,");
|
|
5937
|
+
lines.push(" attributes: Extract<TEvent, { name: TName }>['attributes']");
|
|
5938
|
+
lines.push(") => void;");
|
|
5939
|
+
return lines;
|
|
5940
|
+
}
|
|
5941
|
+
nodeIdToTypeName(nodeId) {
|
|
5942
|
+
return nodeId.split(/[-_]/).map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
5943
|
+
}
|
|
5944
|
+
eventNameToTypeName(eventName) {
|
|
5945
|
+
return eventName.split(".").map((part) => part.charAt(0).toUpperCase() + part.slice(1)).join("");
|
|
5946
|
+
}
|
|
5947
|
+
fieldTypeToTsType(fieldSchema) {
|
|
5948
|
+
switch (fieldSchema.type) {
|
|
5949
|
+
case "string":
|
|
5950
|
+
return "string";
|
|
5951
|
+
case "number":
|
|
5952
|
+
return "number";
|
|
5953
|
+
case "boolean":
|
|
5954
|
+
return "boolean";
|
|
5955
|
+
case "array":
|
|
5956
|
+
return "any[]";
|
|
5957
|
+
case "object":
|
|
5958
|
+
return "Record<string, any>";
|
|
5959
|
+
default:
|
|
5960
|
+
return "any";
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
generateFilename(canvas) {
|
|
5964
|
+
var _a;
|
|
5965
|
+
const name = ((_a = canvas.pv) == null ? void 0 : _a.name) || "canvas";
|
|
5966
|
+
const kebab = name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
5967
|
+
return `${kebab}.types.ts`;
|
|
5968
|
+
}
|
|
5969
|
+
}
|
|
5970
|
+
function generateTypes(canvas, options = { language: "typescript" }) {
|
|
5971
|
+
const generator = getGenerator(options.language);
|
|
5972
|
+
return generator.generate(canvas, options);
|
|
5973
|
+
}
|
|
5974
|
+
function getGenerator(language) {
|
|
5975
|
+
switch (language) {
|
|
5976
|
+
case "typescript":
|
|
5977
|
+
return new TypeScriptGenerator();
|
|
5978
|
+
case "python":
|
|
5979
|
+
throw new Error("Python generator not yet implemented. See TypeScriptGenerator as reference.");
|
|
5980
|
+
case "go":
|
|
5981
|
+
throw new Error("Go generator not yet implemented. See TypeScriptGenerator as reference.");
|
|
5982
|
+
case "rust":
|
|
5983
|
+
throw new Error("Rust generator not yet implemented. See TypeScriptGenerator as reference.");
|
|
5984
|
+
default:
|
|
5985
|
+
throw new Error(`Unsupported language: ${language}`);
|
|
5986
|
+
}
|
|
5987
|
+
}
|
|
5988
|
+
const generatorRegistry = {
|
|
5989
|
+
generators: /* @__PURE__ */ new Map([
|
|
5990
|
+
["typescript", new TypeScriptGenerator()]
|
|
5991
|
+
]),
|
|
5992
|
+
register(generator) {
|
|
5993
|
+
this.generators.set(generator.language, generator);
|
|
5994
|
+
},
|
|
5995
|
+
get(language) {
|
|
5996
|
+
return this.generators.get(language);
|
|
5997
|
+
},
|
|
5998
|
+
list() {
|
|
5999
|
+
return Array.from(this.generators.keys());
|
|
6000
|
+
}
|
|
6001
|
+
};
|
|
6002
|
+
const DEFAULT_OPTIONS$4 = {
|
|
6003
|
+
groupByService: true,
|
|
6004
|
+
layout: "hierarchical",
|
|
6005
|
+
nodeWidth: 200,
|
|
6006
|
+
nodeHeight: 60,
|
|
6007
|
+
horizontalSpacing: 50,
|
|
6008
|
+
verticalSpacing: 80,
|
|
6009
|
+
includeAttributes: true,
|
|
6010
|
+
minDurationMs: 0,
|
|
6011
|
+
kindColors: {
|
|
6012
|
+
SERVER: "#4f46e5",
|
|
6013
|
+
// Indigo
|
|
6014
|
+
CLIENT: "#0891b2",
|
|
6015
|
+
// Cyan
|
|
6016
|
+
PRODUCER: "#059669",
|
|
6017
|
+
// Emerald
|
|
6018
|
+
CONSUMER: "#059669",
|
|
6019
|
+
// Emerald
|
|
6020
|
+
INTERNAL: "#6b7280"
|
|
6021
|
+
// Gray
|
|
6022
|
+
}
|
|
6023
|
+
};
|
|
6024
|
+
function kindToShape(kind) {
|
|
6025
|
+
const shapes = {
|
|
6026
|
+
SERVER: "hexagon",
|
|
6027
|
+
CLIENT: "diamond",
|
|
6028
|
+
PRODUCER: "rectangle",
|
|
6029
|
+
CONSUMER: "rectangle",
|
|
6030
|
+
INTERNAL: "circle"
|
|
6031
|
+
};
|
|
6032
|
+
return shapes[kind] ?? "rectangle";
|
|
6033
|
+
}
|
|
6034
|
+
function getServiceName(span) {
|
|
6035
|
+
var _a;
|
|
6036
|
+
return ((_a = span.resource) == null ? void 0 : _a["service.name"]) ?? "unknown";
|
|
6037
|
+
}
|
|
6038
|
+
function formatDuration(ms) {
|
|
6039
|
+
if (ms < 1)
|
|
6040
|
+
return `${(ms * 1e3).toFixed(0)}μs`;
|
|
6041
|
+
if (ms < 1e3)
|
|
6042
|
+
return `${ms.toFixed(2)}ms`;
|
|
6043
|
+
return `${(ms / 1e3).toFixed(2)}s`;
|
|
6044
|
+
}
|
|
6045
|
+
function groupByTraceId(spans) {
|
|
6046
|
+
const traces = /* @__PURE__ */ new Map();
|
|
6047
|
+
for (const span of spans) {
|
|
6048
|
+
const existing = traces.get(span.traceId) ?? [];
|
|
6049
|
+
existing.push(span);
|
|
6050
|
+
traces.set(span.traceId, existing);
|
|
6051
|
+
}
|
|
6052
|
+
return traces;
|
|
6053
|
+
}
|
|
6054
|
+
function buildSpanTree(spans) {
|
|
6055
|
+
const spanMap = new Map(spans.map((s) => [s.spanId, s]));
|
|
6056
|
+
const childMap = /* @__PURE__ */ new Map();
|
|
6057
|
+
for (const span of spans) {
|
|
6058
|
+
const parentId = span.parentSpanId ?? void 0;
|
|
6059
|
+
const siblings = childMap.get(parentId) ?? [];
|
|
6060
|
+
siblings.push(span);
|
|
6061
|
+
childMap.set(parentId, siblings);
|
|
6062
|
+
}
|
|
6063
|
+
function buildNode(span, depth, index2) {
|
|
6064
|
+
const children = (childMap.get(span.spanId) ?? []).sort((a, b) => a.startTime - b.startTime).map((child, i) => buildNode(child, depth + 1, i));
|
|
6065
|
+
return { span, children, depth, index: index2 };
|
|
6066
|
+
}
|
|
6067
|
+
const roots = spans.filter((s) => !s.parentSpanId || !spanMap.has(s.parentSpanId));
|
|
6068
|
+
return roots.sort((a, b) => a.startTime - b.startTime).map((root, i) => buildNode(root, 0, i));
|
|
6069
|
+
}
|
|
6070
|
+
function calculateHierarchicalLayout(trees, options) {
|
|
6071
|
+
const positions = /* @__PURE__ */ new Map();
|
|
6072
|
+
const { nodeWidth, nodeHeight, horizontalSpacing, verticalSpacing } = options;
|
|
6073
|
+
const depthWidths = /* @__PURE__ */ new Map();
|
|
6074
|
+
function layoutNode(node, offsetX2) {
|
|
6075
|
+
const { span, children, depth } = node;
|
|
6076
|
+
const currentX = depthWidths.get(depth) ?? offsetX2;
|
|
6077
|
+
const y = depth * (nodeHeight + verticalSpacing);
|
|
6078
|
+
if (children.length === 0) {
|
|
6079
|
+
positions.set(span.spanId, { x: currentX, y });
|
|
6080
|
+
depthWidths.set(depth, currentX + nodeWidth + horizontalSpacing);
|
|
6081
|
+
return currentX + nodeWidth / 2;
|
|
6082
|
+
}
|
|
6083
|
+
const childCenters = [];
|
|
6084
|
+
for (const child of children) {
|
|
6085
|
+
const center = layoutNode(child, currentX);
|
|
6086
|
+
childCenters.push(center);
|
|
6087
|
+
}
|
|
6088
|
+
const minCenter = Math.min(...childCenters);
|
|
6089
|
+
const maxCenter = Math.max(...childCenters);
|
|
6090
|
+
const parentCenter = (minCenter + maxCenter) / 2;
|
|
6091
|
+
const parentX = parentCenter - nodeWidth / 2;
|
|
6092
|
+
positions.set(span.spanId, { x: Math.max(currentX, parentX), y });
|
|
6093
|
+
const newWidth = Math.max(depthWidths.get(depth) ?? 0, parentX + nodeWidth + horizontalSpacing);
|
|
6094
|
+
depthWidths.set(depth, newWidth);
|
|
6095
|
+
return parentCenter;
|
|
6096
|
+
}
|
|
6097
|
+
let offsetX = 0;
|
|
6098
|
+
for (const tree of trees) {
|
|
6099
|
+
layoutNode(tree, offsetX);
|
|
6100
|
+
offsetX = Math.max(...Array.from(depthWidths.values())) + horizontalSpacing;
|
|
6101
|
+
}
|
|
6102
|
+
return positions;
|
|
6103
|
+
}
|
|
6104
|
+
function spanToNode(span, position, options) {
|
|
6105
|
+
var _a;
|
|
6106
|
+
const { nodeWidth, nodeHeight, kindColors, includeAttributes } = options;
|
|
6107
|
+
const statusCode = ((_a = span.status) == null ? void 0 : _a.code) ?? "UNSET";
|
|
6108
|
+
return {
|
|
6109
|
+
id: span.spanId,
|
|
6110
|
+
type: "text",
|
|
6111
|
+
x: position.x,
|
|
6112
|
+
y: position.y,
|
|
6113
|
+
width: nodeWidth,
|
|
6114
|
+
height: nodeHeight,
|
|
6115
|
+
text: span.name,
|
|
6116
|
+
color: statusCode === "ERROR" ? 1 : void 0,
|
|
6117
|
+
// Red for errors
|
|
6118
|
+
pv: {
|
|
6119
|
+
nodeType: "span",
|
|
6120
|
+
name: span.name,
|
|
6121
|
+
description: formatDuration(span.duration),
|
|
6122
|
+
shape: kindToShape(span.kind),
|
|
6123
|
+
fill: statusCode === "ERROR" ? "#ef4444" : kindColors[span.kind],
|
|
6124
|
+
states: {
|
|
6125
|
+
[statusCode]: {
|
|
6126
|
+
color: statusCode === "OK" ? "#22c55e" : statusCode === "ERROR" ? "#ef4444" : "#6b7280",
|
|
6127
|
+
label: statusCode
|
|
6128
|
+
}
|
|
6129
|
+
},
|
|
6130
|
+
otel: {
|
|
6131
|
+
kind: "instance",
|
|
6132
|
+
category: "span"
|
|
6133
|
+
},
|
|
6134
|
+
...includeAttributes && span.attributes && Object.keys(span.attributes).length > 0 ? {
|
|
6135
|
+
dataSchema: Object.fromEntries(Object.entries(span.attributes).map(([key, value]) => [
|
|
6136
|
+
key,
|
|
6137
|
+
{ type: typeof value, required: false }
|
|
6138
|
+
]))
|
|
6139
|
+
} : {}
|
|
6140
|
+
}
|
|
6141
|
+
};
|
|
6142
|
+
}
|
|
6143
|
+
function createEdge(parentSpanId, childSpanId, isCrossService) {
|
|
6144
|
+
return {
|
|
6145
|
+
id: `edge-${parentSpanId}-${childSpanId}`,
|
|
6146
|
+
fromNode: parentSpanId,
|
|
6147
|
+
toNode: childSpanId,
|
|
6148
|
+
fromSide: "bottom",
|
|
6149
|
+
toSide: "top",
|
|
6150
|
+
toEnd: "arrow",
|
|
6151
|
+
pv: {
|
|
6152
|
+
edgeType: "span-child",
|
|
6153
|
+
style: isCrossService ? "dashed" : "solid",
|
|
6154
|
+
width: isCrossService ? 2 : 1
|
|
6155
|
+
}
|
|
6156
|
+
};
|
|
6157
|
+
}
|
|
6158
|
+
function createServiceGroup(serviceName, spans, positions, options) {
|
|
6159
|
+
const serviceSpans = spans.filter((s) => getServiceName(s) === serviceName);
|
|
6160
|
+
if (serviceSpans.length === 0)
|
|
6161
|
+
return null;
|
|
6162
|
+
const servicePositions = serviceSpans.map((s) => positions.get(s.spanId)).filter((p) => p !== void 0);
|
|
6163
|
+
if (servicePositions.length === 0)
|
|
6164
|
+
return null;
|
|
6165
|
+
const minX = Math.min(...servicePositions.map((p) => p.x));
|
|
6166
|
+
const maxX = Math.max(...servicePositions.map((p) => p.x));
|
|
6167
|
+
const minY = Math.min(...servicePositions.map((p) => p.y));
|
|
6168
|
+
const maxY = Math.max(...servicePositions.map((p) => p.y));
|
|
6169
|
+
const padding = 20;
|
|
6170
|
+
return {
|
|
6171
|
+
id: `service-${serviceName}`,
|
|
6172
|
+
type: "group",
|
|
6173
|
+
x: minX - padding,
|
|
6174
|
+
y: minY - padding - 30,
|
|
6175
|
+
// Extra space for label
|
|
6176
|
+
width: maxX - minX + options.nodeWidth + padding * 2,
|
|
6177
|
+
height: maxY - minY + options.nodeHeight + padding * 2 + 30,
|
|
6178
|
+
label: serviceName,
|
|
6179
|
+
pv: {
|
|
6180
|
+
nodeType: "service",
|
|
6181
|
+
name: serviceName,
|
|
6182
|
+
icon: "server"
|
|
6183
|
+
}
|
|
6184
|
+
};
|
|
6185
|
+
}
|
|
6186
|
+
function traceToCanvas(traceExport, options = {}) {
|
|
6187
|
+
const opts = { ...DEFAULT_OPTIONS$4, ...options };
|
|
6188
|
+
const spans = traceExport.spans.filter((s) => s.duration >= opts.minDurationMs);
|
|
6189
|
+
if (spans.length === 0) {
|
|
6190
|
+
return {
|
|
6191
|
+
canvas: {
|
|
6192
|
+
nodes: [],
|
|
6193
|
+
edges: [],
|
|
6194
|
+
pv: {
|
|
6195
|
+
version: "1.0.0",
|
|
6196
|
+
name: "Empty Trace"
|
|
6197
|
+
}
|
|
6198
|
+
},
|
|
6199
|
+
stats: {
|
|
6200
|
+
traceCount: 0,
|
|
6201
|
+
spanCount: 0,
|
|
6202
|
+
serviceCount: 0,
|
|
6203
|
+
maxDepth: 0
|
|
6204
|
+
}
|
|
6205
|
+
};
|
|
6206
|
+
}
|
|
6207
|
+
const traceGroups = groupByTraceId(spans);
|
|
6208
|
+
const allTrees = [];
|
|
6209
|
+
for (const traceSpans of traceGroups.values()) {
|
|
6210
|
+
allTrees.push(...buildSpanTree(traceSpans));
|
|
6211
|
+
}
|
|
6212
|
+
const positions = calculateHierarchicalLayout(allTrees, opts);
|
|
6213
|
+
const spanNodes = spans.map((span) => {
|
|
6214
|
+
const position = positions.get(span.spanId) ?? { x: 0, y: 0 };
|
|
6215
|
+
return spanToNode(span, position, opts);
|
|
6216
|
+
});
|
|
6217
|
+
const spanMap = new Map(spans.map((s) => [s.spanId, s]));
|
|
6218
|
+
const edges = spans.filter((span) => span.parentSpanId && spanMap.has(span.parentSpanId)).map((span) => {
|
|
6219
|
+
const parent = spanMap.get(span.parentSpanId);
|
|
6220
|
+
const isCrossService = getServiceName(span) !== getServiceName(parent);
|
|
6221
|
+
return createEdge(span.parentSpanId, span.spanId, isCrossService);
|
|
6222
|
+
});
|
|
6223
|
+
const serviceGroups = [];
|
|
6224
|
+
if (opts.groupByService) {
|
|
6225
|
+
const services = new Set(spans.map(getServiceName));
|
|
6226
|
+
for (const service of services) {
|
|
6227
|
+
const group = createServiceGroup(service, spans, positions, opts);
|
|
6228
|
+
if (group)
|
|
6229
|
+
serviceGroups.push(group);
|
|
6230
|
+
}
|
|
6231
|
+
}
|
|
6232
|
+
const maxDepth = Math.max(...allTrees.flatMap(function getDepths(tree) {
|
|
6233
|
+
return [tree.depth, ...tree.children.flatMap(getDepths)];
|
|
6234
|
+
}));
|
|
6235
|
+
const canvas = {
|
|
6236
|
+
nodes: [...serviceGroups, ...spanNodes],
|
|
6237
|
+
edges,
|
|
6238
|
+
pv: {
|
|
6239
|
+
version: "1.0.0",
|
|
6240
|
+
name: `Trace: ${traceExport.serviceName}`,
|
|
6241
|
+
description: `Exported at ${traceExport.exportedAt}`,
|
|
6242
|
+
nodeTypes: {
|
|
6243
|
+
span: {
|
|
6244
|
+
description: "OpenTelemetry span from trace",
|
|
6245
|
+
shape: "rectangle"
|
|
6246
|
+
},
|
|
6247
|
+
service: {
|
|
6248
|
+
description: "Service grouping",
|
|
6249
|
+
icon: "server",
|
|
6250
|
+
shape: "rectangle"
|
|
6251
|
+
}
|
|
6252
|
+
},
|
|
6253
|
+
edgeTypes: {
|
|
6254
|
+
"span-child": {
|
|
6255
|
+
label: "Child span",
|
|
6256
|
+
directed: true
|
|
6257
|
+
}
|
|
6258
|
+
},
|
|
6259
|
+
display: {
|
|
6260
|
+
layout: "manual",
|
|
6261
|
+
// We've already laid out the nodes
|
|
6262
|
+
animations: {
|
|
6263
|
+
enabled: true,
|
|
6264
|
+
speed: 1
|
|
6265
|
+
}
|
|
6266
|
+
}
|
|
6267
|
+
}
|
|
6268
|
+
};
|
|
6269
|
+
return {
|
|
6270
|
+
canvas,
|
|
6271
|
+
stats: {
|
|
6272
|
+
traceCount: traceGroups.size,
|
|
6273
|
+
spanCount: spans.length,
|
|
6274
|
+
serviceCount: new Set(spans.map(getServiceName)).size,
|
|
6275
|
+
maxDepth
|
|
6276
|
+
}
|
|
6277
|
+
};
|
|
6278
|
+
}
|
|
6279
|
+
function traceToCanvasJson(traceExport, options = {}) {
|
|
6280
|
+
const { canvas } = traceToCanvas(traceExport, options);
|
|
6281
|
+
return JSON.stringify(canvas, null, 2);
|
|
6282
|
+
}
|
|
5665
6283
|
class SessionManager {
|
|
5666
6284
|
constructor(config = {}) {
|
|
5667
6285
|
this.sessions = /* @__PURE__ */ new Map();
|
|
@@ -9582,6 +10200,7 @@ function isRuleDisabled(severity) {
|
|
|
9582
10200
|
}
|
|
9583
10201
|
return false;
|
|
9584
10202
|
}
|
|
10203
|
+
const tracer = trace.getTracer("principal-view-core");
|
|
9585
10204
|
class GraphRulesEngine {
|
|
9586
10205
|
constructor() {
|
|
9587
10206
|
this.rules = /* @__PURE__ */ new Map();
|
|
@@ -9631,45 +10250,148 @@ class GraphRulesEngine {
|
|
|
9631
10250
|
* Lint a configuration against all enabled rules
|
|
9632
10251
|
*/
|
|
9633
10252
|
async lint(configuration, options) {
|
|
9634
|
-
const
|
|
9635
|
-
|
|
9636
|
-
|
|
9637
|
-
|
|
10253
|
+
const span = tracer.startSpan("rules.lint", {
|
|
10254
|
+
attributes: {
|
|
10255
|
+
"lint.config.path": (options == null ? void 0 : options.configPath) ?? "unknown",
|
|
10256
|
+
"lint.rules.total": this.rules.size,
|
|
10257
|
+
"lint.library.provided": !!(options == null ? void 0 : options.library)
|
|
9638
10258
|
}
|
|
9639
|
-
|
|
9640
|
-
|
|
9641
|
-
|
|
9642
|
-
|
|
9643
|
-
|
|
9644
|
-
|
|
9645
|
-
|
|
9646
|
-
|
|
9647
|
-
|
|
9648
|
-
|
|
10259
|
+
});
|
|
10260
|
+
try {
|
|
10261
|
+
const violations = [];
|
|
10262
|
+
let rulesExecuted = 0;
|
|
10263
|
+
let rulesSkipped = 0;
|
|
10264
|
+
span.addEvent("lint.started", {
|
|
10265
|
+
"rules.registered": this.rules.size
|
|
10266
|
+
});
|
|
10267
|
+
for (const [ruleId, rule] of this.rules) {
|
|
10268
|
+
if (!this.shouldRunRule(rule, options)) {
|
|
10269
|
+
rulesSkipped++;
|
|
10270
|
+
continue;
|
|
9649
10271
|
}
|
|
9650
|
-
|
|
9651
|
-
|
|
9652
|
-
|
|
9653
|
-
|
|
9654
|
-
|
|
9655
|
-
|
|
9656
|
-
|
|
10272
|
+
const context = this.buildRuleContext(configuration, rule, options);
|
|
10273
|
+
const effectiveSeverity = this.getEffectiveSeverity(rule, options);
|
|
10274
|
+
if (effectiveSeverity === "off") {
|
|
10275
|
+
rulesSkipped++;
|
|
10276
|
+
continue;
|
|
10277
|
+
}
|
|
10278
|
+
const ruleSpan = tracer.startSpan("rule.execute", {
|
|
10279
|
+
attributes: {
|
|
10280
|
+
"rule.id": ruleId,
|
|
10281
|
+
"rule.category": rule.category,
|
|
10282
|
+
"rule.severity": effectiveSeverity,
|
|
10283
|
+
"rule.name": rule.name,
|
|
10284
|
+
"parent.span.id": span.spanContext().spanId
|
|
10285
|
+
}
|
|
9657
10286
|
});
|
|
10287
|
+
try {
|
|
10288
|
+
const ruleStartTime = Date.now();
|
|
10289
|
+
const ruleViolations = await rule.check(context);
|
|
10290
|
+
const ruleDuration = Date.now() - ruleStartTime;
|
|
10291
|
+
rulesExecuted++;
|
|
10292
|
+
for (const violation of ruleViolations) {
|
|
10293
|
+
violation.severity = effectiveSeverity;
|
|
10294
|
+
violations.push(violation);
|
|
10295
|
+
}
|
|
10296
|
+
ruleSpan.addEvent("rule.completed", {
|
|
10297
|
+
"rule.violations.count": ruleViolations.length,
|
|
10298
|
+
"rule.duration.ms": ruleDuration
|
|
10299
|
+
});
|
|
10300
|
+
if (ruleViolations.length > 0) {
|
|
10301
|
+
span.addEvent("violations.detected", {
|
|
10302
|
+
"rule.id": ruleId,
|
|
10303
|
+
"rule.category": rule.category,
|
|
10304
|
+
"violations.count": ruleViolations.length,
|
|
10305
|
+
"violations.severity": effectiveSeverity
|
|
10306
|
+
});
|
|
10307
|
+
}
|
|
10308
|
+
ruleSpan.setStatus({ code: SpanStatusCode.OK });
|
|
10309
|
+
} catch (error) {
|
|
10310
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10311
|
+
violations.push({
|
|
10312
|
+
ruleId,
|
|
10313
|
+
severity: "error",
|
|
10314
|
+
message: `Rule "${ruleId}" threw an error: ${errorMessage}`,
|
|
10315
|
+
impact: "Rule could not complete validation",
|
|
10316
|
+
fixable: false
|
|
10317
|
+
});
|
|
10318
|
+
ruleSpan.addEvent("rule.error", {
|
|
10319
|
+
"error.message": errorMessage,
|
|
10320
|
+
"error.type": error instanceof Error ? error.constructor.name : "unknown"
|
|
10321
|
+
});
|
|
10322
|
+
ruleSpan.setStatus({
|
|
10323
|
+
code: SpanStatusCode.ERROR,
|
|
10324
|
+
message: errorMessage
|
|
10325
|
+
});
|
|
10326
|
+
span.addEvent("rule.execution.error", {
|
|
10327
|
+
"rule.id": ruleId,
|
|
10328
|
+
"error.message": errorMessage
|
|
10329
|
+
});
|
|
10330
|
+
} finally {
|
|
10331
|
+
ruleSpan.end();
|
|
10332
|
+
}
|
|
9658
10333
|
}
|
|
10334
|
+
const result = this.buildResult(violations);
|
|
10335
|
+
span.addEvent("lint.completed", {
|
|
10336
|
+
"lint.rules.executed": rulesExecuted,
|
|
10337
|
+
"lint.rules.skipped": rulesSkipped,
|
|
10338
|
+
"lint.violations.total": violations.length,
|
|
10339
|
+
"lint.violations.errors": result.errorCount,
|
|
10340
|
+
"lint.violations.warnings": result.warningCount,
|
|
10341
|
+
"lint.violations.fixable": result.fixableCount
|
|
10342
|
+
});
|
|
10343
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
10344
|
+
return result;
|
|
10345
|
+
} catch (error) {
|
|
10346
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10347
|
+
span.setStatus({
|
|
10348
|
+
code: SpanStatusCode.ERROR,
|
|
10349
|
+
message: errorMessage
|
|
10350
|
+
});
|
|
10351
|
+
span.recordException(error instanceof Error ? error : new Error(errorMessage));
|
|
10352
|
+
throw error;
|
|
10353
|
+
} finally {
|
|
10354
|
+
span.end();
|
|
9659
10355
|
}
|
|
9660
|
-
return this.buildResult(violations);
|
|
9661
10356
|
}
|
|
9662
10357
|
/**
|
|
9663
10358
|
* Lint a configuration with VGC config file settings applied
|
|
9664
10359
|
*/
|
|
9665
10360
|
async lintWithConfig(configuration, privuConfig, options) {
|
|
9666
|
-
const
|
|
9667
|
-
|
|
9668
|
-
|
|
9669
|
-
|
|
9670
|
-
|
|
9671
|
-
|
|
10361
|
+
const span = tracer.startSpan("rules.lintWithConfig", {
|
|
10362
|
+
attributes: {
|
|
10363
|
+
"config.path": (options == null ? void 0 : options.configPath) ?? "unknown",
|
|
10364
|
+
"config.has.rules": !!privuConfig.rules,
|
|
10365
|
+
"config.has.library": !!privuConfig.library
|
|
10366
|
+
}
|
|
9672
10367
|
});
|
|
10368
|
+
try {
|
|
10369
|
+
span.addEvent("config.parsing");
|
|
10370
|
+
const { ruleOptions, severityOverrides, disabledRules } = this.parsePrivuConfigRules(privuConfig.rules);
|
|
10371
|
+
span.addEvent("config.parsed", {
|
|
10372
|
+
"config.rule.options.count": ruleOptions.size,
|
|
10373
|
+
"config.severity.overrides.count": severityOverrides.size,
|
|
10374
|
+
"config.disabled.rules.count": disabledRules.length
|
|
10375
|
+
});
|
|
10376
|
+
const result = await this.lint(configuration, {
|
|
10377
|
+
...options,
|
|
10378
|
+
ruleOptions,
|
|
10379
|
+
severityOverrides,
|
|
10380
|
+
disabledRules: [...(options == null ? void 0 : options.disabledRules) ?? [], ...disabledRules]
|
|
10381
|
+
});
|
|
10382
|
+
span.setStatus({ code: SpanStatusCode.OK });
|
|
10383
|
+
return result;
|
|
10384
|
+
} catch (error) {
|
|
10385
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
10386
|
+
span.setStatus({
|
|
10387
|
+
code: SpanStatusCode.ERROR,
|
|
10388
|
+
message: errorMessage
|
|
10389
|
+
});
|
|
10390
|
+
span.recordException(error instanceof Error ? error : new Error(errorMessage));
|
|
10391
|
+
throw error;
|
|
10392
|
+
} finally {
|
|
10393
|
+
span.end();
|
|
10394
|
+
}
|
|
9673
10395
|
}
|
|
9674
10396
|
/**
|
|
9675
10397
|
* Check if a rule should run based on options
|
|
@@ -11465,6 +12187,8 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
11465
12187
|
DEFAULT_INCLUDE_PATTERNS,
|
|
11466
12188
|
EventProcessor,
|
|
11467
12189
|
EventRecorderService,
|
|
12190
|
+
EventValidationError,
|
|
12191
|
+
EventValidator,
|
|
11468
12192
|
GraphConverter,
|
|
11469
12193
|
GraphInstrumentationHelper,
|
|
11470
12194
|
GraphRulesEngine,
|
|
@@ -11474,6 +12198,7 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
11474
12198
|
PathBasedEventProcessor,
|
|
11475
12199
|
PathMatcher,
|
|
11476
12200
|
SessionManager,
|
|
12201
|
+
TypeScriptGenerator,
|
|
11477
12202
|
VALID_RULE_IDS,
|
|
11478
12203
|
VALID_SEVERITIES,
|
|
11479
12204
|
ValidationEngine,
|
|
@@ -11482,8 +12207,11 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
11482
12207
|
createDefaultRulesEngine,
|
|
11483
12208
|
createResourceSignature,
|
|
11484
12209
|
createRulesEngine,
|
|
12210
|
+
createValidatedEmitter,
|
|
11485
12211
|
deadEndStates,
|
|
11486
12212
|
formatConfigErrors,
|
|
12213
|
+
generateTypes,
|
|
12214
|
+
generatorRegistry,
|
|
11487
12215
|
getConfigNameFromFilename: getConfigNameFromFilename$1,
|
|
11488
12216
|
getDefaultConfig,
|
|
11489
12217
|
hasPVExtension,
|
|
@@ -11515,6 +12243,8 @@ const dist = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty
|
|
|
11515
12243
|
resolveCanvasColor,
|
|
11516
12244
|
signatureToKey,
|
|
11517
12245
|
stateTransitionReferences,
|
|
12246
|
+
traceToCanvas,
|
|
12247
|
+
traceToCanvasJson,
|
|
11518
12248
|
unreachableStates,
|
|
11519
12249
|
validActionPatterns,
|
|
11520
12250
|
validColorFormat,
|
|
@@ -47123,7 +47853,7 @@ const lucideReact = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineP
|
|
|
47123
47853
|
createLucideIcon: createLucideIcon$1,
|
|
47124
47854
|
icons: index
|
|
47125
47855
|
}, Symbol.toStringTag, { value: "Module" }));
|
|
47126
|
-
const require$$
|
|
47856
|
+
const require$$3 = /* @__PURE__ */ getAugmentedNamespace(lucideReact);
|
|
47127
47857
|
var hasRequiredIconResolver;
|
|
47128
47858
|
function requireIconResolver() {
|
|
47129
47859
|
if (hasRequiredIconResolver) return iconResolver;
|
|
@@ -47169,7 +47899,7 @@ function requireIconResolver() {
|
|
|
47169
47899
|
iconResolver.Icon = void 0;
|
|
47170
47900
|
iconResolver.resolveIcon = resolveIcon;
|
|
47171
47901
|
const jsx_runtime_1 = require$$0;
|
|
47172
|
-
const LucideIcons = __importStar(require$$
|
|
47902
|
+
const LucideIcons = __importStar(require$$3);
|
|
47173
47903
|
function resolveIcon(icon, size = 20, className) {
|
|
47174
47904
|
if (!icon)
|
|
47175
47905
|
return null;
|
|
@@ -47309,13 +48039,24 @@ function requireCustomNode() {
|
|
|
47309
48039
|
const react_2 = /* @__PURE__ */ requireUmd();
|
|
47310
48040
|
const iconResolver_1 = requireIconResolver();
|
|
47311
48041
|
const NodeTooltip_1 = requireNodeTooltip();
|
|
48042
|
+
function hexToLightColor(hexColor, lightness = 0.88) {
|
|
48043
|
+
const hex = hexColor.replace("#", "");
|
|
48044
|
+
const r = parseInt(hex.substring(0, 2), 16);
|
|
48045
|
+
const g = parseInt(hex.substring(2, 4), 16);
|
|
48046
|
+
const b = parseInt(hex.substring(4, 6), 16);
|
|
48047
|
+
const newR = Math.round(r + (255 - r) * lightness);
|
|
48048
|
+
const newG = Math.round(g + (255 - g) * lightness);
|
|
48049
|
+
const newB = Math.round(b + (255 - b) * lightness);
|
|
48050
|
+
const toHex = (n) => n.toString(16).padStart(2, "0");
|
|
48051
|
+
return `#${toHex(newR)}${toHex(newG)}${toHex(newB)}`;
|
|
48052
|
+
}
|
|
47312
48053
|
const CustomNode$1 = ({ data, selected, dragging }) => {
|
|
47313
48054
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o;
|
|
47314
48055
|
const [isHovered, setIsHovered] = (0, react_1.useState)(false);
|
|
47315
48056
|
const showTooltip = isHovered && !dragging;
|
|
47316
48057
|
const nodeRef = (0, react_1.useRef)(null);
|
|
47317
48058
|
const nodeProps = data;
|
|
47318
|
-
const { typeDefinition, state, hasViolations, data: nodeData, animationType, animationDuration = 1e3, editable = false, tooltipsEnabled = true } = nodeProps;
|
|
48059
|
+
const { typeDefinition, state, hasViolations, data: nodeData, animationType, animationDuration = 1e3, editable = false, tooltipsEnabled = true, isHighlighted = false } = nodeProps;
|
|
47319
48060
|
const otelInfo = nodeData == null ? void 0 : nodeData.otel;
|
|
47320
48061
|
const description = nodeData == null ? void 0 : nodeData.description;
|
|
47321
48062
|
const getOtelBadgeColor = (kind) => {
|
|
@@ -47388,7 +48129,7 @@ function requireCustomNode() {
|
|
|
47388
48129
|
const getShapeStyles = () => {
|
|
47389
48130
|
const baseStyles = {
|
|
47390
48131
|
padding: "12px 16px",
|
|
47391
|
-
backgroundColor: isGroup ? "rgba(255, 255, 255, 0.7)" :
|
|
48132
|
+
backgroundColor: isGroup ? "rgba(255, 255, 255, 0.7)" : hexToLightColor(fillColor),
|
|
47392
48133
|
color: "#000",
|
|
47393
48134
|
border: `2px solid ${hasViolations ? "#D0021B" : strokeColor}`,
|
|
47394
48135
|
fontSize: "12px",
|
|
@@ -47404,7 +48145,7 @@ function requireCustomNode() {
|
|
|
47404
48145
|
alignItems: "center",
|
|
47405
48146
|
justifyContent: isGroup ? "flex-start" : "center",
|
|
47406
48147
|
gap: "4px",
|
|
47407
|
-
boxShadow: selected ? `0 0 0 2px ${strokeColor}` : "0 2px 4px rgba(0,0,0,0.1)",
|
|
48148
|
+
boxShadow: isHighlighted ? `0 0 0 3px #3b82f6, 0 0 20px rgba(59, 130, 246, 0.5)` : selected ? `0 0 0 2px ${strokeColor}` : "0 2px 4px rgba(0,0,0,0.1)",
|
|
47408
48149
|
transition: "box-shadow 0.2s ease",
|
|
47409
48150
|
animationDuration: animationType ? `${animationDuration}ms` : void 0,
|
|
47410
48151
|
boxSizing: "border-box"
|
|
@@ -47481,7 +48222,7 @@ function requireCustomNode() {
|
|
|
47481
48222
|
right: hexagonBorderWidth,
|
|
47482
48223
|
bottom: hexagonBorderWidth,
|
|
47483
48224
|
clipPath: hexagonClipPath,
|
|
47484
|
-
backgroundColor:
|
|
48225
|
+
backgroundColor: hexToLightColor(fillColor),
|
|
47485
48226
|
color: "#000",
|
|
47486
48227
|
display: "flex",
|
|
47487
48228
|
flexDirection: "column",
|
|
@@ -47513,7 +48254,7 @@ function requireCustomNode() {
|
|
|
47513
48254
|
right: diamondBorderWidth,
|
|
47514
48255
|
bottom: diamondBorderWidth,
|
|
47515
48256
|
clipPath: diamondClipPath,
|
|
47516
|
-
backgroundColor:
|
|
48257
|
+
backgroundColor: hexToLightColor(fillColor),
|
|
47517
48258
|
color: "#000",
|
|
47518
48259
|
display: "flex",
|
|
47519
48260
|
flexDirection: "column",
|
|
@@ -48613,7 +49354,7 @@ function requireGraphRenderer() {
|
|
|
48613
49354
|
zIndex: 5
|
|
48614
49355
|
}, children: [(0, jsx_runtime_1.jsx)("line", { x1: screenX, y1: screenY - size, x2: screenX, y2: screenY + size, stroke: color, strokeWidth, opacity: 0.7 }), (0, jsx_runtime_1.jsx)("line", { x1: screenX - size, y1: screenY, x2: screenX + size, y2: screenY, stroke: color, strokeWidth, opacity: 0.7 }), (0, jsx_runtime_1.jsx)("circle", { cx: screenX, cy: screenY, r: 3, fill: color, opacity: 0.7 })] });
|
|
48615
49356
|
};
|
|
48616
|
-
const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges, violations = [], configName: _configName, showMinimap =
|
|
49357
|
+
const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges, violations = [], configName: _configName, showMinimap = false, showControls = true, showBackground = true, backgroundVariant = "dots", backgroundGap, showCenterIndicator = false, showTooltips = true, fitViewDuration = 200, highlightedNodeId, events = [], onEventProcessed, editable = false, onPendingChangesChange, onEditStateChange, editStateRef, onSourceClick }) => {
|
|
48617
49358
|
const { fitView } = (0, react_2.useReactFlow)();
|
|
48618
49359
|
const { theme } = (0, industry_theme_1.useTheme)();
|
|
48619
49360
|
const [animationState, setAnimationState] = (0, react_1.useState)({
|
|
@@ -48831,7 +49572,7 @@ function requireGraphRenderer() {
|
|
|
48831
49572
|
return;
|
|
48832
49573
|
}
|
|
48833
49574
|
if (uniqueTypes.length === 1) {
|
|
48834
|
-
|
|
49575
|
+
createEdge2(connection.source, connection.target, uniqueTypes[0], connection.sourceHandle ?? void 0, connection.targetHandle ?? void 0);
|
|
48835
49576
|
} else {
|
|
48836
49577
|
setPendingConnection({
|
|
48837
49578
|
from: connection.source,
|
|
@@ -48842,7 +49583,7 @@ function requireGraphRenderer() {
|
|
|
48842
49583
|
});
|
|
48843
49584
|
}
|
|
48844
49585
|
}, [editable, nodes, configuration.allowedConnections]);
|
|
48845
|
-
const
|
|
49586
|
+
const createEdge2 = (0, react_1.useCallback)((from, to, type2, sourceHandle, targetHandle) => {
|
|
48846
49587
|
const edgeId = `${from}-${to}-${type2}-${Date.now()}`;
|
|
48847
49588
|
const newEdge = {
|
|
48848
49589
|
id: edgeId,
|
|
@@ -48867,9 +49608,9 @@ function requireGraphRenderer() {
|
|
|
48867
49608
|
const handleEdgeTypeSelect = (0, react_1.useCallback)((type2) => {
|
|
48868
49609
|
if (!pendingConnection)
|
|
48869
49610
|
return;
|
|
48870
|
-
|
|
49611
|
+
createEdge2(pendingConnection.from, pendingConnection.to, type2, pendingConnection.sourceHandle, pendingConnection.targetHandle);
|
|
48871
49612
|
setPendingConnection(null);
|
|
48872
|
-
}, [pendingConnection,
|
|
49613
|
+
}, [pendingConnection, createEdge2]);
|
|
48873
49614
|
const handleCancelEdgeTypePicker = (0, react_1.useCallback)(() => {
|
|
48874
49615
|
setPendingConnection(null);
|
|
48875
49616
|
}, []);
|
|
@@ -49064,7 +49805,7 @@ function requireGraphRenderer() {
|
|
|
49064
49805
|
}
|
|
49065
49806
|
}, [events, onEventProcessed]);
|
|
49066
49807
|
const xyflowNodesBase = (0, react_1.useMemo)(() => {
|
|
49067
|
-
const converted = (0, graphConverter_1.convertToXYFlowNodes)(
|
|
49808
|
+
const converted = (0, graphConverter_1.convertToXYFlowNodes)(localNodes, configuration, violations);
|
|
49068
49809
|
return converted.map((node) => {
|
|
49069
49810
|
const animation = animationState.nodeAnimations[node.id];
|
|
49070
49811
|
const pendingPosition = editStateRef.current.positionChanges.get(node.id);
|
|
@@ -49075,6 +49816,7 @@ function requireGraphRenderer() {
|
|
|
49075
49816
|
...node.data,
|
|
49076
49817
|
editable,
|
|
49077
49818
|
tooltipsEnabled: showTooltips,
|
|
49819
|
+
isHighlighted: highlightedNodeId === node.id,
|
|
49078
49820
|
...animation ? {
|
|
49079
49821
|
animationType: animation.type,
|
|
49080
49822
|
animationDuration: animation.duration
|
|
@@ -49082,7 +49824,7 @@ function requireGraphRenderer() {
|
|
|
49082
49824
|
}
|
|
49083
49825
|
};
|
|
49084
49826
|
});
|
|
49085
|
-
}, [
|
|
49827
|
+
}, [localNodes, configuration, violations, animationState.nodeAnimations, editable, showTooltips, highlightedNodeId, editStateRef]);
|
|
49086
49828
|
const baseNodesKey = (0, react_1.useMemo)(() => {
|
|
49087
49829
|
return nodes.map((n) => n.id).sort().join(",");
|
|
49088
49830
|
}, [nodes]);
|
|
@@ -49144,8 +49886,9 @@ function requireGraphRenderer() {
|
|
|
49144
49886
|
}, [editable, updateEditState]);
|
|
49145
49887
|
const xyflowEdges = (0, react_1.useMemo)(() => {
|
|
49146
49888
|
const converted = (0, graphConverter_1.convertToXYFlowEdges)(edges, configuration, violations);
|
|
49147
|
-
|
|
49889
|
+
const mappedEdges = converted.map((edge) => {
|
|
49148
49890
|
const animation = animationState.edgeAnimations[edge.id];
|
|
49891
|
+
const isSelected = selectedEdgeIds.has(edge.id);
|
|
49149
49892
|
return {
|
|
49150
49893
|
...edge,
|
|
49151
49894
|
data: {
|
|
@@ -49156,10 +49899,21 @@ function requireGraphRenderer() {
|
|
|
49156
49899
|
animationDuration: animation.duration,
|
|
49157
49900
|
animationDirection: animation.direction
|
|
49158
49901
|
} : {}
|
|
49159
|
-
}
|
|
49902
|
+
},
|
|
49903
|
+
// Add z-index to help with stacking (selected edges get higher values)
|
|
49904
|
+
zIndex: isSelected ? 1e3 : 0
|
|
49160
49905
|
};
|
|
49161
49906
|
});
|
|
49162
|
-
|
|
49907
|
+
return mappedEdges.sort((a, b) => {
|
|
49908
|
+
const aSelected = selectedEdgeIds.has(a.id);
|
|
49909
|
+
const bSelected = selectedEdgeIds.has(b.id);
|
|
49910
|
+
if (aSelected && !bSelected)
|
|
49911
|
+
return 1;
|
|
49912
|
+
if (!aSelected && bSelected)
|
|
49913
|
+
return -1;
|
|
49914
|
+
return 0;
|
|
49915
|
+
});
|
|
49916
|
+
}, [edges, configuration, violations, animationState.edgeAnimations, showTooltips, selectedEdgeIds]);
|
|
49163
49917
|
(0, react_1.useEffect)(() => {
|
|
49164
49918
|
const timeoutId = setTimeout(() => {
|
|
49165
49919
|
fitView({
|
|
@@ -49389,8 +50143,8 @@ function requireGraphRenderer() {
|
|
|
49389
50143
|
}, children: (0, jsx_runtime_1.jsx)("p", { children: "No canvas data provided." }) });
|
|
49390
50144
|
}
|
|
49391
50145
|
const { configuration, nodes, edges } = canvasData;
|
|
49392
|
-
const { violations, configName, showMinimap, showControls, showBackground, backgroundVariant, backgroundGap, showCenterIndicator, showTooltips, fitViewDuration, events, onEventProcessed, editable, onPendingChangesChange, onSourceClick } = props;
|
|
49393
|
-
return (0, jsx_runtime_1.jsx)("div", { className, style: { width, height, position: "relative" }, children: (0, jsx_runtime_1.jsx)(react_2.ReactFlowProvider, { children: (0, jsx_runtime_1.jsx)(GraphRendererInner, { configuration, nodes, edges, violations, configName, showMinimap, showControls, showBackground, backgroundVariant, backgroundGap, showCenterIndicator, showTooltips, fitViewDuration, events, onEventProcessed, editable, onPendingChangesChange, editStateRef, onSourceClick }) }) });
|
|
50146
|
+
const { violations, configName, showMinimap, showControls, showBackground, backgroundVariant, backgroundGap, showCenterIndicator, showTooltips, fitViewDuration, highlightedNodeId, events, onEventProcessed, editable, onPendingChangesChange, onSourceClick } = props;
|
|
50147
|
+
return (0, jsx_runtime_1.jsx)("div", { className, style: { width, height, position: "relative" }, children: (0, jsx_runtime_1.jsx)(react_2.ReactFlowProvider, { children: (0, jsx_runtime_1.jsx)(GraphRendererInner, { configuration, nodes, edges, violations, configName, showMinimap, showControls, showBackground, backgroundVariant, backgroundGap, showCenterIndicator, showTooltips, fitViewDuration, highlightedNodeId, events, onEventProcessed, editable, onPendingChangesChange, editStateRef, onSourceClick }) }) });
|
|
49394
50148
|
});
|
|
49395
50149
|
exports$1.GraphRenderer.displayName = "GraphRenderer";
|
|
49396
50150
|
})(GraphRenderer);
|
|
@@ -49481,6 +50235,141 @@ function requireConfigurationSelector() {
|
|
|
49481
50235
|
ConfigurationSelector.ConfigurationSelector = ConfigurationSelector$1;
|
|
49482
50236
|
return ConfigurationSelector;
|
|
49483
50237
|
}
|
|
50238
|
+
var TestEventPanel = {};
|
|
50239
|
+
var hasRequiredTestEventPanel;
|
|
50240
|
+
function requireTestEventPanel() {
|
|
50241
|
+
if (hasRequiredTestEventPanel) return TestEventPanel;
|
|
50242
|
+
hasRequiredTestEventPanel = 1;
|
|
50243
|
+
Object.defineProperty(TestEventPanel, "__esModule", { value: true });
|
|
50244
|
+
TestEventPanel.TestEventPanel = void 0;
|
|
50245
|
+
const jsx_runtime_1 = require$$0;
|
|
50246
|
+
const react_1 = React2;
|
|
50247
|
+
const industry_theme_1 = requireCjs();
|
|
50248
|
+
const lucide_react_1 = require$$3;
|
|
50249
|
+
const TestEventPanel$1 = ({ spans, currentSpanIndex, currentEventIndex, highlightedPhase }) => {
|
|
50250
|
+
const { theme } = (0, industry_theme_1.useTheme)();
|
|
50251
|
+
const [showHelp, setShowHelp] = (0, react_1.useState)(false);
|
|
50252
|
+
const currentSpan = spans[currentSpanIndex];
|
|
50253
|
+
const eventsUpToNow = (currentSpan == null ? void 0 : currentSpan.events.slice(0, currentEventIndex + 1)) || [];
|
|
50254
|
+
return (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
50255
|
+
width: "100%",
|
|
50256
|
+
height: "100%",
|
|
50257
|
+
backgroundColor: theme.colors.background,
|
|
50258
|
+
color: theme.colors.text,
|
|
50259
|
+
padding: "20px",
|
|
50260
|
+
fontFamily: theme.fonts.monospace,
|
|
50261
|
+
fontSize: "14px",
|
|
50262
|
+
overflow: "auto",
|
|
50263
|
+
boxSizing: "border-box"
|
|
50264
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: "15px" }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: "bold", fontSize: "18px" }, children: "Wide Event Pattern - Code Journey" }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowHelp(true), style: {
|
|
50265
|
+
background: "transparent",
|
|
50266
|
+
border: "none",
|
|
50267
|
+
cursor: "pointer",
|
|
50268
|
+
padding: "4px",
|
|
50269
|
+
display: "flex",
|
|
50270
|
+
alignItems: "center",
|
|
50271
|
+
color: theme.colors.textMuted
|
|
50272
|
+
}, onMouseEnter: (e) => {
|
|
50273
|
+
e.currentTarget.style.color = theme.colors.text;
|
|
50274
|
+
}, onMouseLeave: (e) => {
|
|
50275
|
+
e.currentTarget.style.color = theme.colors.textMuted;
|
|
50276
|
+
}, children: (0, jsx_runtime_1.jsx)(lucide_react_1.HelpCircle, { size: 20 }) })] }), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: "13px", color: theme.colors.textMuted, marginBottom: "15px" }, children: ["Test: ", (currentSpan == null ? void 0 : currentSpan.name) || "Loading..."] }), showHelp && (0, jsx_runtime_1.jsx)("div", { style: {
|
|
50277
|
+
position: "fixed",
|
|
50278
|
+
top: 0,
|
|
50279
|
+
left: 0,
|
|
50280
|
+
right: 0,
|
|
50281
|
+
bottom: 0,
|
|
50282
|
+
backgroundColor: "rgba(0, 0, 0, 0.7)",
|
|
50283
|
+
display: "flex",
|
|
50284
|
+
alignItems: "center",
|
|
50285
|
+
justifyContent: "center",
|
|
50286
|
+
zIndex: 9999
|
|
50287
|
+
}, onClick: () => setShowHelp(false), children: (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
50288
|
+
backgroundColor: theme.colors.background,
|
|
50289
|
+
color: theme.colors.text,
|
|
50290
|
+
padding: "24px",
|
|
50291
|
+
borderRadius: "8px",
|
|
50292
|
+
maxWidth: "600px",
|
|
50293
|
+
border: `1px solid ${theme.colors.border}`
|
|
50294
|
+
}, onClick: (e) => e.stopPropagation(), children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: "bold", fontSize: "18px", marginBottom: "16px" }, children: "How to Read This Panel" }), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: "14px", marginBottom: "16px", lineHeight: "1.6" }, children: [(0, jsx_runtime_1.jsx)("p", { style: { marginBottom: "12px" }, children: (0, jsx_runtime_1.jsx)("strong", { children: "Watch how execution flows through files:" }) }), (0, jsx_runtime_1.jsxs)("ul", { style: { marginLeft: "20px", marginBottom: "16px" }, children: [(0, jsx_runtime_1.jsx)("li", { style: { marginBottom: "8px" }, children: (0, jsx_runtime_1.jsx)("span", { style: { color: "#60a5fa" }, children: "Blue = Test file" }) }), (0, jsx_runtime_1.jsx)("li", { children: (0, jsx_runtime_1.jsx)("span", { style: { color: "#4ade80" }, children: "Green → Code under test" }) })] }), (0, jsx_runtime_1.jsx)("p", { style: { marginBottom: "12px" }, children: (0, jsx_runtime_1.jsx)("strong", { children: "Span Context (Static)" }) }), (0, jsx_runtime_1.jsx)("pre", { style: {
|
|
50295
|
+
background: theme.colors.surface,
|
|
50296
|
+
padding: "12px",
|
|
50297
|
+
borderRadius: "4px",
|
|
50298
|
+
fontSize: "13px",
|
|
50299
|
+
overflow: "auto"
|
|
50300
|
+
}, children: `{
|
|
50301
|
+
"test.file": "GraphConverter.test.ts",
|
|
50302
|
+
"test.suite": "GraphConverter",
|
|
50303
|
+
"test.result": "pass"
|
|
50304
|
+
}` })] }), (0, jsx_runtime_1.jsx)("button", { onClick: () => setShowHelp(false), style: {
|
|
50305
|
+
padding: "8px 16px",
|
|
50306
|
+
backgroundColor: theme.colors.primary,
|
|
50307
|
+
color: theme.colors.background,
|
|
50308
|
+
border: "none",
|
|
50309
|
+
borderRadius: "4px",
|
|
50310
|
+
cursor: "pointer",
|
|
50311
|
+
fontSize: "14px",
|
|
50312
|
+
fontWeight: 500
|
|
50313
|
+
}, children: "Got it" })] }) }), currentSpan && (0, jsx_runtime_1.jsx)(jsx_runtime_1.Fragment, { children: (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("div", { style: {
|
|
50314
|
+
color: "#4ade80",
|
|
50315
|
+
fontWeight: "bold",
|
|
50316
|
+
marginBottom: "8px",
|
|
50317
|
+
fontSize: "15px"
|
|
50318
|
+
}, children: "Event Timeline (Context Mutations)" }), eventsUpToNow.map((event, idx) => {
|
|
50319
|
+
const filepath = event.attributes["code.filepath"];
|
|
50320
|
+
const lineno = event.attributes["code.lineno"];
|
|
50321
|
+
const isCodeUnderTest = filepath && filepath !== "GraphConverter.test.ts";
|
|
50322
|
+
const eventPhase = event.name.split(".")[0];
|
|
50323
|
+
const isHighlighted = highlightedPhase === eventPhase;
|
|
50324
|
+
return (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
50325
|
+
marginBottom: "12px",
|
|
50326
|
+
paddingBottom: "12px",
|
|
50327
|
+
borderBottom: idx < eventsUpToNow.length - 1 ? `1px solid ${theme.colors.border}` : "none",
|
|
50328
|
+
opacity: highlightedPhase && !isHighlighted ? 0.4 : 1,
|
|
50329
|
+
transition: "opacity 0.2s ease",
|
|
50330
|
+
transform: isHighlighted ? "scale(1.02)" : "scale(1)",
|
|
50331
|
+
backgroundColor: isHighlighted ? theme.colors.surface : "transparent",
|
|
50332
|
+
padding: isHighlighted ? "8px" : "0",
|
|
50333
|
+
borderRadius: "4px"
|
|
50334
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: {
|
|
50335
|
+
display: "flex",
|
|
50336
|
+
justifyContent: "space-between",
|
|
50337
|
+
alignItems: "center",
|
|
50338
|
+
marginBottom: "4px",
|
|
50339
|
+
gap: "8px"
|
|
50340
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: { color: "#f59e0b", fontSize: "13px", flexShrink: 0 }, children: [idx + 1, ". ", event.name] }), filepath && (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
50341
|
+
fontSize: "12px",
|
|
50342
|
+
color: isCodeUnderTest ? "#4ade80" : "#60a5fa",
|
|
50343
|
+
fontFamily: "monospace",
|
|
50344
|
+
background: isCodeUnderTest ? "#064e3b" : "#1e3a8a",
|
|
50345
|
+
padding: "2px 6px",
|
|
50346
|
+
borderRadius: "3px",
|
|
50347
|
+
flexShrink: 1,
|
|
50348
|
+
minWidth: 0,
|
|
50349
|
+
overflow: "hidden",
|
|
50350
|
+
textOverflow: "ellipsis",
|
|
50351
|
+
whiteSpace: "nowrap"
|
|
50352
|
+
}, children: [isCodeUnderTest && "→ ", filepath, ":", lineno] })] }), (0, jsx_runtime_1.jsx)("pre", { style: {
|
|
50353
|
+
background: theme.colors.surface,
|
|
50354
|
+
padding: "8px",
|
|
50355
|
+
borderRadius: "4px",
|
|
50356
|
+
margin: 0,
|
|
50357
|
+
fontSize: "12px",
|
|
50358
|
+
lineHeight: "1.4",
|
|
50359
|
+
overflow: "auto",
|
|
50360
|
+
maxWidth: "100%"
|
|
50361
|
+
}, children: JSON.stringify(Object.fromEntries(Object.entries(event.attributes).filter(([key]) => key !== "code.filepath" && key !== "code.lineno")), null, 2) })] }, idx);
|
|
50362
|
+
})] }) }), (0, jsx_runtime_1.jsxs)("div", { style: {
|
|
50363
|
+
marginTop: "20px",
|
|
50364
|
+
paddingTop: "15px",
|
|
50365
|
+
borderTop: `1px solid ${theme.colors.border}`,
|
|
50366
|
+
fontSize: "13px",
|
|
50367
|
+
color: theme.colors.textMuted
|
|
50368
|
+
}, children: [(0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: "8px" }, children: [(0, jsx_runtime_1.jsx)("strong", { children: "Total tests:" }), " ", spans.length] }), (0, jsx_runtime_1.jsxs)("div", { style: { marginBottom: "8px" }, children: [(0, jsx_runtime_1.jsx)("strong", { children: "Pattern:" }), " One span per test + event timeline"] }), (0, jsx_runtime_1.jsxs)("div", { children: [(0, jsx_runtime_1.jsx)("strong", { children: "Status:" }), " ", (0, jsx_runtime_1.jsx)("span", { style: { color: "#4ade80" }, children: "All Passed ✓" })] })] })] });
|
|
50369
|
+
};
|
|
50370
|
+
TestEventPanel.TestEventPanel = TestEventPanel$1;
|
|
50371
|
+
return TestEventPanel;
|
|
50372
|
+
}
|
|
49484
50373
|
var GenericNode = {};
|
|
49485
50374
|
var hasRequiredGenericNode;
|
|
49486
50375
|
function requireGenericNode() {
|
|
@@ -49525,7 +50414,7 @@ function requireDist() {
|
|
|
49525
50414
|
hasRequiredDist = 1;
|
|
49526
50415
|
(function(exports$1) {
|
|
49527
50416
|
Object.defineProperty(exports$1, "__esModule", { value: true });
|
|
49528
|
-
exports$1.resolveIcon = exports$1.Icon = exports$1.convertToXYFlowEdges = exports$1.convertToXYFlowNodes = exports$1.NodeTooltip = exports$1.CustomEdge = exports$1.GenericEdge = exports$1.CustomNode = exports$1.GenericNode = exports$1.ConfigurationSelector = exports$1.NodeInfoPanel = exports$1.EdgeInfoPanel = exports$1.MetricsDashboard = exports$1.EventLog = exports$1.GraphRenderer = void 0;
|
|
50417
|
+
exports$1.resolveIcon = exports$1.Icon = exports$1.convertToXYFlowEdges = exports$1.convertToXYFlowNodes = exports$1.NodeTooltip = exports$1.CustomEdge = exports$1.GenericEdge = exports$1.CustomNode = exports$1.GenericNode = exports$1.TestEventPanel = exports$1.ConfigurationSelector = exports$1.NodeInfoPanel = exports$1.EdgeInfoPanel = exports$1.MetricsDashboard = exports$1.EventLog = exports$1.GraphRenderer = void 0;
|
|
49529
50418
|
var GraphRenderer_1 = requireGraphRenderer();
|
|
49530
50419
|
Object.defineProperty(exports$1, "GraphRenderer", { enumerable: true, get: function() {
|
|
49531
50420
|
return GraphRenderer_1.GraphRenderer;
|
|
@@ -49550,6 +50439,10 @@ function requireDist() {
|
|
|
49550
50439
|
Object.defineProperty(exports$1, "ConfigurationSelector", { enumerable: true, get: function() {
|
|
49551
50440
|
return ConfigurationSelector_1.ConfigurationSelector;
|
|
49552
50441
|
} });
|
|
50442
|
+
var TestEventPanel_1 = requireTestEventPanel();
|
|
50443
|
+
Object.defineProperty(exports$1, "TestEventPanel", { enumerable: true, get: function() {
|
|
50444
|
+
return TestEventPanel_1.TestEventPanel;
|
|
50445
|
+
} });
|
|
49553
50446
|
var GenericNode_1 = requireGenericNode();
|
|
49554
50447
|
Object.defineProperty(exports$1, "GenericNode", { enumerable: true, get: function() {
|
|
49555
50448
|
return GenericNode_1.GenericNode;
|
|
@@ -51848,12 +52741,12 @@ const TraceViewerPanel = ({
|
|
|
51848
52741
|
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.15)",
|
|
51849
52742
|
zIndex: 100
|
|
51850
52743
|
},
|
|
51851
|
-
children: state.availableTraces.map((
|
|
51852
|
-
const isSelected =
|
|
52744
|
+
children: state.availableTraces.map((trace2) => {
|
|
52745
|
+
const isSelected = trace2.id === state.selectedTraceId;
|
|
51853
52746
|
return /* @__PURE__ */ jsxs(
|
|
51854
52747
|
"button",
|
|
51855
52748
|
{
|
|
51856
|
-
onClick: () => handleTraceSelect(
|
|
52749
|
+
onClick: () => handleTraceSelect(trace2.id),
|
|
51857
52750
|
style: {
|
|
51858
52751
|
display: "flex",
|
|
51859
52752
|
flexDirection: "column",
|
|
@@ -51878,22 +52771,22 @@ const TraceViewerPanel = ({
|
|
|
51878
52771
|
fontSize: theme.fontSizes[1],
|
|
51879
52772
|
fontWeight: isSelected ? 500 : 400
|
|
51880
52773
|
},
|
|
51881
|
-
children:
|
|
52774
|
+
children: trace2.name
|
|
51882
52775
|
}
|
|
51883
52776
|
),
|
|
51884
|
-
|
|
52777
|
+
trace2.packageName && /* @__PURE__ */ jsx(
|
|
51885
52778
|
"span",
|
|
51886
52779
|
{
|
|
51887
52780
|
style: {
|
|
51888
52781
|
fontSize: theme.fontSizes[0],
|
|
51889
52782
|
color: theme.colors.textMuted
|
|
51890
52783
|
},
|
|
51891
|
-
children:
|
|
52784
|
+
children: trace2.packageName
|
|
51892
52785
|
}
|
|
51893
52786
|
)
|
|
51894
52787
|
]
|
|
51895
52788
|
},
|
|
51896
|
-
|
|
52789
|
+
trace2.id
|
|
51897
52790
|
);
|
|
51898
52791
|
})
|
|
51899
52792
|
}
|
|
@@ -52170,6 +53063,58 @@ const ExecutionStats = ({ metadata }) => {
|
|
|
52170
53063
|
}
|
|
52171
53064
|
);
|
|
52172
53065
|
};
|
|
53066
|
+
function mapEventToNodeId(event, canvas) {
|
|
53067
|
+
var _a, _b, _c;
|
|
53068
|
+
if (!canvas || !canvas.nodes || canvas.nodes.length === 0) {
|
|
53069
|
+
return null;
|
|
53070
|
+
}
|
|
53071
|
+
for (const node of canvas.nodes) {
|
|
53072
|
+
const pvEvents = (_a = node.pv) == null ? void 0 : _a.events;
|
|
53073
|
+
if (pvEvents && typeof pvEvents === "object") {
|
|
53074
|
+
if (event.name in pvEvents) {
|
|
53075
|
+
return node.id;
|
|
53076
|
+
}
|
|
53077
|
+
}
|
|
53078
|
+
}
|
|
53079
|
+
if (event.attributes) {
|
|
53080
|
+
for (const node of canvas.nodes) {
|
|
53081
|
+
const resourceMatch = (_c = (_b = node.pv) == null ? void 0 : _b.otel) == null ? void 0 : _c.resourceMatch;
|
|
53082
|
+
if (resourceMatch && typeof resourceMatch === "object") {
|
|
53083
|
+
const matches = Object.entries(resourceMatch).every(([key, pattern]) => {
|
|
53084
|
+
var _a2;
|
|
53085
|
+
const value = (_a2 = event.attributes) == null ? void 0 : _a2[key];
|
|
53086
|
+
if (value === void 0) return false;
|
|
53087
|
+
if (typeof pattern === "string" && pattern === "*") {
|
|
53088
|
+
return true;
|
|
53089
|
+
}
|
|
53090
|
+
return value === pattern;
|
|
53091
|
+
});
|
|
53092
|
+
if (matches) {
|
|
53093
|
+
return node.id;
|
|
53094
|
+
}
|
|
53095
|
+
}
|
|
53096
|
+
}
|
|
53097
|
+
}
|
|
53098
|
+
return null;
|
|
53099
|
+
}
|
|
53100
|
+
function buildEventToNodeMap(canvas) {
|
|
53101
|
+
var _a;
|
|
53102
|
+
const map2 = /* @__PURE__ */ new Map();
|
|
53103
|
+
if (!canvas || !canvas.nodes) {
|
|
53104
|
+
return map2;
|
|
53105
|
+
}
|
|
53106
|
+
for (const node of canvas.nodes) {
|
|
53107
|
+
const pvEvents = (_a = node.pv) == null ? void 0 : _a.events;
|
|
53108
|
+
if (pvEvents && typeof pvEvents === "object") {
|
|
53109
|
+
for (const eventName of Object.keys(pvEvents)) {
|
|
53110
|
+
if (!map2.has(eventName)) {
|
|
53111
|
+
map2.set(eventName, node.id);
|
|
53112
|
+
}
|
|
53113
|
+
}
|
|
53114
|
+
}
|
|
53115
|
+
}
|
|
53116
|
+
return map2;
|
|
53117
|
+
}
|
|
52173
53118
|
const ExecutionViewerPanel = ({
|
|
52174
53119
|
context,
|
|
52175
53120
|
actions,
|
|
@@ -52188,7 +53133,8 @@ const ExecutionViewerPanel = ({
|
|
|
52188
53133
|
showExecutionSelector: false,
|
|
52189
53134
|
isPlaying: false,
|
|
52190
53135
|
currentSpanIndex: 0,
|
|
52191
|
-
currentEventIndex: 0
|
|
53136
|
+
currentEventIndex: 0,
|
|
53137
|
+
highlightedNodeId: null
|
|
52192
53138
|
});
|
|
52193
53139
|
const contextRef = useRef(context);
|
|
52194
53140
|
const actionsRef = useRef(actions);
|
|
@@ -52199,6 +53145,7 @@ const ExecutionViewerPanel = ({
|
|
|
52199
53145
|
const selectedExecutionIdRef = useRef(null);
|
|
52200
53146
|
selectedExecutionIdRef.current = state.selectedExecutionId;
|
|
52201
53147
|
const playbackTimerRef = useRef(null);
|
|
53148
|
+
const eventNodeMapRef = useRef(/* @__PURE__ */ new Map());
|
|
52202
53149
|
const loadExecution = useCallback(async (executionId) => {
|
|
52203
53150
|
setState((prev) => ({ ...prev, loading: prev.canvas === null, error: null }));
|
|
52204
53151
|
try {
|
|
@@ -52283,6 +53230,11 @@ const ExecutionViewerPanel = ({
|
|
|
52283
53230
|
console.warn("[ExecutionViewer] Failed to load canvas:", error);
|
|
52284
53231
|
}
|
|
52285
53232
|
}
|
|
53233
|
+
if (canvas) {
|
|
53234
|
+
eventNodeMapRef.current = buildEventToNodeMap(canvas);
|
|
53235
|
+
} else {
|
|
53236
|
+
eventNodeMapRef.current = /* @__PURE__ */ new Map();
|
|
53237
|
+
}
|
|
52286
53238
|
setState((prev) => ({
|
|
52287
53239
|
...prev,
|
|
52288
53240
|
canvas,
|
|
@@ -52293,7 +53245,8 @@ const ExecutionViewerPanel = ({
|
|
|
52293
53245
|
availableExecutions,
|
|
52294
53246
|
selectedExecutionId: selectedExecution2.id,
|
|
52295
53247
|
currentSpanIndex: 0,
|
|
52296
|
-
currentEventIndex: 0
|
|
53248
|
+
currentEventIndex: 0,
|
|
53249
|
+
highlightedNodeId: null
|
|
52297
53250
|
}));
|
|
52298
53251
|
} catch (error) {
|
|
52299
53252
|
console.error("[ExecutionViewer] Error loading execution:", error);
|
|
@@ -52331,7 +53284,8 @@ const ExecutionViewerPanel = ({
|
|
|
52331
53284
|
...prev,
|
|
52332
53285
|
isPlaying: false,
|
|
52333
53286
|
currentSpanIndex: 0,
|
|
52334
|
-
currentEventIndex: 0
|
|
53287
|
+
currentEventIndex: 0,
|
|
53288
|
+
highlightedNodeId: null
|
|
52335
53289
|
}));
|
|
52336
53290
|
}, []);
|
|
52337
53291
|
useEffect(() => {
|
|
@@ -52349,22 +53303,30 @@ const ExecutionViewerPanel = ({
|
|
|
52349
53303
|
}, 0);
|
|
52350
53304
|
playbackTimerRef.current = setInterval(() => {
|
|
52351
53305
|
setState((prev) => {
|
|
52352
|
-
var _a2;
|
|
53306
|
+
var _a2, _b;
|
|
52353
53307
|
const spans2 = prev.execution ? ExecutionLoader.getSpans(prev.execution) : [];
|
|
52354
53308
|
if (spans2.length === 0) return { ...prev, isPlaying: false };
|
|
52355
53309
|
const currentSpan = spans2[prev.currentSpanIndex];
|
|
52356
53310
|
const spanEventCount = ((_a2 = currentSpan == null ? void 0 : currentSpan.events) == null ? void 0 : _a2.length) || 0;
|
|
53311
|
+
let newSpanIndex = prev.currentSpanIndex;
|
|
53312
|
+
let newEventIndex = prev.currentEventIndex;
|
|
52357
53313
|
if (prev.currentEventIndex < spanEventCount - 1) {
|
|
52358
|
-
|
|
52359
|
-
}
|
|
52360
|
-
|
|
52361
|
-
|
|
52362
|
-
|
|
52363
|
-
|
|
52364
|
-
currentEventIndex: 0
|
|
52365
|
-
};
|
|
53314
|
+
newEventIndex = prev.currentEventIndex + 1;
|
|
53315
|
+
} else if (prev.currentSpanIndex < spans2.length - 1) {
|
|
53316
|
+
newSpanIndex = prev.currentSpanIndex + 1;
|
|
53317
|
+
newEventIndex = 0;
|
|
53318
|
+
} else {
|
|
53319
|
+
return { ...prev, isPlaying: false };
|
|
52366
53320
|
}
|
|
52367
|
-
|
|
53321
|
+
const newSpan = spans2[newSpanIndex];
|
|
53322
|
+
const newEvent = (_b = newSpan == null ? void 0 : newSpan.events) == null ? void 0 : _b[newEventIndex];
|
|
53323
|
+
const highlightedNodeId = newEvent ? mapEventToNodeId(newEvent, prev.canvas) : null;
|
|
53324
|
+
return {
|
|
53325
|
+
...prev,
|
|
53326
|
+
currentSpanIndex: newSpanIndex,
|
|
53327
|
+
currentEventIndex: newEventIndex,
|
|
53328
|
+
highlightedNodeId
|
|
53329
|
+
};
|
|
52368
53330
|
});
|
|
52369
53331
|
}, 800);
|
|
52370
53332
|
return () => {
|
|
@@ -52657,7 +53619,8 @@ const ExecutionViewerPanel = ({
|
|
|
52657
53619
|
showControls: true,
|
|
52658
53620
|
showBackground: true,
|
|
52659
53621
|
backgroundVariant: "lines",
|
|
52660
|
-
showTooltips: true
|
|
53622
|
+
showTooltips: true,
|
|
53623
|
+
highlightedNodeId: state.highlightedNodeId
|
|
52661
53624
|
}
|
|
52662
53625
|
) }) : /* @__PURE__ */ jsx(
|
|
52663
53626
|
"div",
|
|
@@ -52714,6 +53677,15 @@ const ExecutionViewerPanel = ({
|
|
|
52714
53677
|
return /* @__PURE__ */ jsxs(
|
|
52715
53678
|
"div",
|
|
52716
53679
|
{
|
|
53680
|
+
onClick: () => {
|
|
53681
|
+
const highlightedNodeId = mapEventToNodeId(event, state.canvas);
|
|
53682
|
+
setState((prev) => ({
|
|
53683
|
+
...prev,
|
|
53684
|
+
currentSpanIndex: spanIdx,
|
|
53685
|
+
currentEventIndex: eventIdx,
|
|
53686
|
+
highlightedNodeId
|
|
53687
|
+
}));
|
|
53688
|
+
},
|
|
52717
53689
|
style: {
|
|
52718
53690
|
padding: "8px",
|
|
52719
53691
|
marginBottom: "4px",
|
|
@@ -52721,7 +53693,8 @@ const ExecutionViewerPanel = ({
|
|
|
52721
53693
|
border: `1px solid ${isActive ? "#3b82f6" : "#333"}`,
|
|
52722
53694
|
borderRadius: "4px",
|
|
52723
53695
|
fontSize: "12px",
|
|
52724
|
-
opacity: isPast ? 0.5 : 1
|
|
53696
|
+
opacity: isPast ? 0.5 : 1,
|
|
53697
|
+
cursor: "pointer"
|
|
52725
53698
|
},
|
|
52726
53699
|
children: [
|
|
52727
53700
|
/* @__PURE__ */ jsx("div", { style: { fontWeight: 600, color: "#fff", marginBottom: "4px" }, children: event.name }),
|