@workflow/web-shared 5.0.0-beta.12 → 5.0.0-beta.13

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.
Files changed (55) hide show
  1. package/dist/components/event-list-view.d.ts.map +1 -1
  2. package/dist/components/event-list-view.js +9 -9
  3. package/dist/components/new-trace-viewer/components/event-list.d.ts +1 -1
  4. package/dist/components/new-trace-viewer/components/event-list.d.ts.map +1 -1
  5. package/dist/components/new-trace-viewer/components/event-list.js +4 -2
  6. package/dist/components/new-trace-viewer/components/timeline.d.ts +1 -1
  7. package/dist/components/new-trace-viewer/components/timeline.d.ts.map +1 -1
  8. package/dist/components/new-trace-viewer/components/timeline.js +4 -4
  9. package/dist/components/new-trace-viewer/context.d.ts +1 -1
  10. package/dist/components/new-trace-viewer/context.d.ts.map +1 -1
  11. package/dist/components/new-trace-viewer/context.js +1 -1
  12. package/dist/components/new-trace-viewer/icons.js +3 -3
  13. package/dist/components/new-trace-viewer/search.d.ts +1 -1
  14. package/dist/components/new-trace-viewer/search.d.ts.map +1 -1
  15. package/dist/components/new-trace-viewer/search.js +1 -1
  16. package/dist/components/new-trace-viewer/trace-viewer.d.ts +2 -2
  17. package/dist/components/new-trace-viewer/trace-viewer.d.ts.map +1 -1
  18. package/dist/components/new-trace-viewer/trace-viewer.js +6 -7
  19. package/dist/components/new-trace-viewer/types.d.ts +2 -0
  20. package/dist/components/new-trace-viewer/types.d.ts.map +1 -1
  21. package/dist/components/new-trace-viewer/types.js +2 -2
  22. package/dist/components/new-trace-viewer/utils.d.ts +1 -1
  23. package/dist/components/new-trace-viewer/utils.d.ts.map +1 -1
  24. package/dist/components/new-trace-viewer/utils.js +1 -1
  25. package/dist/components/sidebar/attribute-panel.d.ts.map +1 -1
  26. package/dist/components/sidebar/attribute-panel.js +7 -7
  27. package/dist/components/sidebar/events-list.d.ts.map +1 -1
  28. package/dist/components/sidebar/events-list.js +7 -7
  29. package/dist/components/trace-viewer-new.d.ts.map +1 -1
  30. package/dist/components/trace-viewer-new.js +2 -3
  31. package/dist/components/ui/error-stack-block.d.ts +17 -10
  32. package/dist/components/ui/error-stack-block.d.ts.map +1 -1
  33. package/dist/components/ui/error-stack-block.js +30 -19
  34. package/package.json +2 -2
  35. package/src/components/event-list-view.tsx +12 -11
  36. package/src/components/new-trace-viewer/components/event-list.tsx +4 -3
  37. package/src/components/new-trace-viewer/components/timeline.tsx +4 -4
  38. package/src/components/new-trace-viewer/context.tsx +1 -1
  39. package/src/components/new-trace-viewer/icons.tsx +2 -2
  40. package/src/components/new-trace-viewer/search.ts +1 -1
  41. package/src/components/new-trace-viewer/trace-viewer.tsx +7 -14
  42. package/src/components/new-trace-viewer/types.ts +2 -0
  43. package/src/components/new-trace-viewer/utils.ts +1 -1
  44. package/src/components/sidebar/attribute-panel.tsx +6 -9
  45. package/src/components/sidebar/events-list.tsx +6 -9
  46. package/src/components/trace-viewer-new.tsx +2 -4
  47. package/src/components/ui/error-stack-block.tsx +51 -31
  48. package/dist/components/new-trace-viewer/detail-panel.d.ts +0 -10
  49. package/dist/components/new-trace-viewer/detail-panel.d.ts.map +0 -1
  50. package/dist/components/new-trace-viewer/detail-panel.js +0 -13
  51. package/dist/components/new-trace-viewer/util/constants.d.ts +0 -1
  52. package/dist/components/new-trace-viewer/util/constants.d.ts.map +0 -1
  53. package/dist/components/new-trace-viewer/util/constants.js +0 -2
  54. package/src/components/new-trace-viewer/detail-panel.tsx +0 -55
  55. package/src/components/new-trace-viewer/util/constants.ts +0 -0
@@ -3,13 +3,21 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { AlertCircle } from 'lucide-react';
4
4
  import { CopyButton } from '../new-trace-viewer/components/copy-button';
5
5
  /**
6
- * Check whether `value` looks like a structured error object with a `stack`
7
- * field that we can render as pre-formatted text.
6
+ * Check whether `value` looks like a structured error object we can render
7
+ * with the error block. Some persisted workflow errors only include a
8
+ * `message`, while runtime errors usually also include `stack`.
8
9
  */
9
- export function isStructuredErrorWithStack(value) {
10
+ export function isStructuredError(value) {
10
11
  return (value != null &&
11
12
  typeof value === 'object' &&
12
- 'stack' in value &&
13
+ (typeof value.message === 'string' ||
14
+ typeof value.stack === 'string'));
15
+ }
16
+ /**
17
+ * Narrower guard kept for callers that specifically need a stack trace.
18
+ */
19
+ export function isStructuredErrorWithStack(value) {
20
+ return (isStructuredError(value) &&
13
21
  typeof value.stack === 'string');
14
22
  }
15
23
  /**
@@ -26,18 +34,21 @@ function deriveTitle(message) {
26
34
  return firstLine.trim();
27
35
  }
28
36
  /**
29
- * Renders an error with a `stack` field as a visually distinct error block.
30
- * Shows the error message with an alert icon at the top, separated from
31
- * the stack trace below.
37
+ * Renders a structured error as a visually distinct error block. Shows the
38
+ * error message with an alert icon at the top, separated from the stack trace
39
+ * or full message below.
32
40
  */
33
- export function ErrorStackBlock({ value, }) {
34
- const stack = value.stack;
41
+ export function ErrorStackBlock({ value }) {
42
+ const stack = typeof value.stack === 'string' ? value.stack : undefined;
35
43
  const message = typeof value.message === 'string' ? value.message : undefined;
36
- // V8's `Error.stack` already starts with `Name: message`, so when the
37
- // body shows the stack it includes the full multi-line message anyway.
38
- // The header just needs the first line.
39
- const title = message ? deriveTitle(message) : undefined;
40
- const copyText = message ? `${message}\n\n${stack}` : stack;
44
+ const body = stack ?? message ?? '';
45
+ // V8's `Error.stack` already starts with `Name: message`; message-only
46
+ // errors use the message as the body so long single-line failures remain
47
+ // readable even when the header truncates.
48
+ const title = message ? deriveTitle(message) : deriveTitle(body);
49
+ const copyText = message && stack && !stack.includes(message)
50
+ ? `${message}\n\n${stack}`
51
+ : body;
41
52
  return (_jsxs("div", { className: "relative overflow-hidden rounded-md border", style: {
42
53
  borderColor: 'var(--ds-red-400)',
43
54
  background: 'var(--ds-red-100)',
@@ -45,13 +56,13 @@ export function ErrorStackBlock({ value, }) {
45
56
  color: 'var(--ds-red-900)',
46
57
  borderBottom: '1px solid var(--ds-red-400)',
47
58
  }, children: [_jsx(AlertCircle, { className: "h-4 w-4 shrink-0" }), _jsx("p", { className: "text-xs font-semibold m-0 truncate",
48
- // The full multi-line message is in the stack body below; the
49
- // header just shows the first line, single-line, with overflow
59
+ // The full message or stack is in the body below; the header just
60
+ // shows the first line, single-line, with overflow
50
61
  // ellipsised so a long title doesn't push the copy button or
51
62
  // wrap into the framed hint/docs lines.
52
- title: message, children: title })] })), _jsx("pre", { className: "px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0", style: {
63
+ title: message, children: title })] })), body && (_jsx("pre", { className: "px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0", style: {
53
64
  color: 'var(--ds-red-900)',
54
65
  background: 'var(--ds-red-200)',
55
- }, children: stack })] }));
66
+ }, children: body }))] }));
56
67
  }
57
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3Itc3RhY2stYmxvY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tcG9uZW50cy91aS9lcnJvci1zdGFjay1ibG9jay50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDOztBQUViLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBRXhFOzs7R0FHRztBQUNILE1BQU0sVUFBVSwwQkFBMEIsQ0FDeEMsS0FBYztJQUVkLE9BQU8sQ0FDTCxLQUFLLElBQUksSUFBSTtRQUNiLE9BQU8sS0FBSyxLQUFLLFFBQVE7UUFDekIsT0FBTyxJQUFJLEtBQUs7UUFDaEIsT0FBUSxLQUFpQyxDQUFDLEtBQUssS0FBSyxRQUFRLENBQzdELENBQUM7QUFDSixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxTQUFTLFdBQVcsQ0FBQyxPQUFlO0lBQ2xDLE1BQU0sU0FBUyxHQUNiLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUFDLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxJQUFJLE9BQU8sQ0FBQztJQUN4RSxPQUFPLFNBQVMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztBQUMxQixDQUFDO0FBRUQ7Ozs7R0FJRztBQUNILE1BQU0sVUFBVSxlQUFlLENBQUMsRUFDOUIsS0FBSyxHQUdOO0lBQ0MsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLEtBQUssQ0FBQztJQUMxQixNQUFNLE9BQU8sR0FBRyxPQUFPLEtBQUssQ0FBQyxPQUFPLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDOUUsc0VBQXNFO0lBQ3RFLHVFQUF1RTtJQUN2RSx3Q0FBd0M7SUFDeEMsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUN6RCxNQUFNLFFBQVEsR0FBRyxPQUFPLENBQUMsQ0FBQyxDQUFDLEdBQUcsT0FBTyxPQUFPLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUM7SUFFNUQsT0FBTyxDQUNMLGVBQ0UsU0FBUyxFQUFDLDRDQUE0QyxFQUN0RCxLQUFLLEVBQUU7WUFDTCxXQUFXLEVBQUUsbUJBQW1CO1lBQ2hDLFVBQVUsRUFBRSxtQkFBbUI7U0FDaEMsYUFFRCxLQUFDLFVBQVUsSUFDVCxRQUFRLEVBQUUsUUFBUSxFQUNsQixTQUFTLEVBQUMsWUFBWSxFQUN0QixTQUFTLEVBQUMsbU5BQW1OLEdBQzdOLEVBRUQsS0FBSyxJQUFJLENBQ1IsZUFDRSxTQUFTLEVBQUMsMkNBQTJDLEVBQ3JELEtBQUssRUFBRTtvQkFDTCxLQUFLLEVBQUUsbUJBQW1CO29CQUMxQixZQUFZLEVBQUUsNkJBQTZCO2lCQUM1QyxhQUVELEtBQUMsV0FBVyxJQUFDLFNBQVMsRUFBQyxrQkFBa0IsR0FBRyxFQUM1QyxZQUNFLFNBQVMsRUFBQyxvQ0FBb0M7d0JBQzlDLDhEQUE4RDt3QkFDOUQsK0RBQStEO3dCQUMvRCw2REFBNkQ7d0JBQzdELHdDQUF3Qzt3QkFDeEMsS0FBSyxFQUFFLE9BQU8sWUFFYixLQUFLLEdBQ0osSUFDQSxDQUNQLEVBQ0QsY0FDRSxTQUFTLEVBQUMsaUZBQWlGLEVBQzNGLEtBQUssRUFBRTtvQkFDTCxLQUFLLEVBQUUsbUJBQW1CO29CQUMxQixVQUFVLEVBQUUsbUJBQW1CO2lCQUNoQyxZQUVBLEtBQUssR0FDRixJQUNGLENBQ1AsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIGNsaWVudCc7XG5cbmltcG9ydCB7IEFsZXJ0Q2lyY2xlIH0gZnJvbSAnbHVjaWRlLXJlYWN0JztcbmltcG9ydCB7IENvcHlCdXR0b24gfSBmcm9tICcuLi9uZXctdHJhY2Utdmlld2VyL2NvbXBvbmVudHMvY29weS1idXR0b24nO1xuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgYHZhbHVlYCBsb29rcyBsaWtlIGEgc3RydWN0dXJlZCBlcnJvciBvYmplY3Qgd2l0aCBhIGBzdGFja2BcbiAqIGZpZWxkIHRoYXQgd2UgY2FuIHJlbmRlciBhcyBwcmUtZm9ybWF0dGVkIHRleHQuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1N0cnVjdHVyZWRFcnJvcldpdGhTdGFjayhcbiAgdmFsdWU6IHVua25vd25cbik6IHZhbHVlIGlzIFJlY29yZDxzdHJpbmcsIHVua25vd24+ICYgeyBzdGFjazogc3RyaW5nIH0ge1xuICByZXR1cm4gKFxuICAgIHZhbHVlICE9IG51bGwgJiZcbiAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmXG4gICAgJ3N0YWNrJyBpbiB2YWx1ZSAmJlxuICAgIHR5cGVvZiAodmFsdWUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLnN0YWNrID09PSAnc3RyaW5nJ1xuICApO1xufVxuXG4vKipcbiAqIFB1bGwgYSBzaG9ydCwgc2luZ2xlLWxpbmUgdGl0bGUgb3V0IG9mIGFuIGVycm9yIG1lc3NhZ2UuXG4gKlxuICogV29ya2Zsb3cncyBzdHJ1Y3R1cmVkIGVycm9yIG1lc3NhZ2VzIGFyZSBtdWx0aS1saW5lIOKAlCB0aGUgZmlyc3QgbGluZSBpc1xuICogdGhlIGhlYWRsaW5lIChgRmFpbGVkIHRvIHNlcmlhbGl6ZSBzdGVwIHJldHVybiB2YWx1ZWApIGFuZCB0aGUgcmVzdCBhcmVcbiAqIGDilbDilrYgaGludDpgIC8gYOKVsOKWtiBkb2NzOmAgZnJhbWVkIGRldGFpbHMuIFRoZSBmdWxsIG1lc3NhZ2UgYmVsb25ncyBpbiB0aGVcbiAqIGJvZHkgb2YgdGhlIGVycm9yIGJsb2NrOyB0aGUgdGl0bGUgc2hvdWxkIGp1c3QgYmUgdGhlIGhlYWRsaW5lIHNvIHRoZVxuICogY2FyZCBzdGF5cyBzY2FubmFibGUuXG4gKi9cbmZ1bmN0aW9uIGRlcml2ZVRpdGxlKG1lc3NhZ2U6IHN0cmluZyk6IHN0cmluZyB7XG4gIGNvbnN0IGZpcnN0TGluZSA9XG4gICAgbWVzc2FnZS5zcGxpdCgnXFxuJykuZmluZCgobGluZSkgPT4gbGluZS50cmltKCkubGVuZ3RoID4gMCkgPz8gbWVzc2FnZTtcbiAgcmV0dXJuIGZpcnN0TGluZS50cmltKCk7XG59XG5cbi8qKlxuICogUmVuZGVycyBhbiBlcnJvciB3aXRoIGEgYHN0YWNrYCBmaWVsZCBhcyBhIHZpc3VhbGx5IGRpc3RpbmN0IGVycm9yIGJsb2NrLlxuICogU2hvd3MgdGhlIGVycm9yIG1lc3NhZ2Ugd2l0aCBhbiBhbGVydCBpY29uIGF0IHRoZSB0b3AsIHNlcGFyYXRlZCBmcm9tXG4gKiB0aGUgc3RhY2sgdHJhY2UgYmVsb3cuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBFcnJvclN0YWNrQmxvY2soe1xuICB2YWx1ZSxcbn06IHtcbiAgdmFsdWU6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ICYgeyBzdGFjazogc3RyaW5nIH07XG59KSB7XG4gIGNvbnN0IHN0YWNrID0gdmFsdWUuc3RhY2s7XG4gIGNvbnN0IG1lc3NhZ2UgPSB0eXBlb2YgdmFsdWUubWVzc2FnZSA9PT0gJ3N0cmluZycgPyB2YWx1ZS5tZXNzYWdlIDogdW5kZWZpbmVkO1xuICAvLyBWOCdzIGBFcnJvci5zdGFja2AgYWxyZWFkeSBzdGFydHMgd2l0aCBgTmFtZTogbWVzc2FnZWAsIHNvIHdoZW4gdGhlXG4gIC8vIGJvZHkgc2hvd3MgdGhlIHN0YWNrIGl0IGluY2x1ZGVzIHRoZSBmdWxsIG11bHRpLWxpbmUgbWVzc2FnZSBhbnl3YXkuXG4gIC8vIFRoZSBoZWFkZXIganVzdCBuZWVkcyB0aGUgZmlyc3QgbGluZS5cbiAgY29uc3QgdGl0bGUgPSBtZXNzYWdlID8gZGVyaXZlVGl0bGUobWVzc2FnZSkgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IGNvcHlUZXh0ID0gbWVzc2FnZSA/IGAke21lc3NhZ2V9XFxuXFxuJHtzdGFja31gIDogc3RhY2s7XG5cbiAgcmV0dXJuIChcbiAgICA8ZGl2XG4gICAgICBjbGFzc05hbWU9XCJyZWxhdGl2ZSBvdmVyZmxvdy1oaWRkZW4gcm91bmRlZC1tZCBib3JkZXJcIlxuICAgICAgc3R5bGU9e3tcbiAgICAgICAgYm9yZGVyQ29sb3I6ICd2YXIoLS1kcy1yZWQtNDAwKScsXG4gICAgICAgIGJhY2tncm91bmQ6ICd2YXIoLS1kcy1yZWQtMTAwKScsXG4gICAgICB9fVxuICAgID5cbiAgICAgIDxDb3B5QnV0dG9uXG4gICAgICAgIGNvcHlUZXh0PXtjb3B5VGV4dH1cbiAgICAgICAgYXJpYUxhYmVsPVwiQ29weSBlcnJvclwiXG4gICAgICAgIGNsYXNzTmFtZT1cImFic29sdXRlIHJpZ2h0LTIgdG9wLTIgZmxleCBoLTYgdy02IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWNlbnRlciByb3VuZGVkLW1kIGJvcmRlciBib3JkZXItcmVkLTQwMCBiZy1yZWQtMTAwIHAtMCB0ZXh0LXJlZC05MDAgdHJhbnNpdGlvbi10cmFuc2Zvcm0gdHJhbnNpdGlvbi1jb2xvcnMgZHVyYXRpb24tMTAwIGhvdmVyOmJnLXJlZC0yMDAgYWN0aXZlOnNjYWxlLTk1XCJcbiAgICAgIC8+XG5cbiAgICAgIHt0aXRsZSAmJiAoXG4gICAgICAgIDxkaXZcbiAgICAgICAgICBjbGFzc05hbWU9XCJmbGV4IGl0ZW1zLWNlbnRlciBnYXAtMiBweC0zIHB5LTIuNSBwci0xMFwiXG4gICAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICAgIGNvbG9yOiAndmFyKC0tZHMtcmVkLTkwMCknLFxuICAgICAgICAgICAgYm9yZGVyQm90dG9tOiAnMXB4IHNvbGlkIHZhcigtLWRzLXJlZC00MDApJyxcbiAgICAgICAgICB9fVxuICAgICAgICA+XG4gICAgICAgICAgPEFsZXJ0Q2lyY2xlIGNsYXNzTmFtZT1cImgtNCB3LTQgc2hyaW5rLTBcIiAvPlxuICAgICAgICAgIDxwXG4gICAgICAgICAgICBjbGFzc05hbWU9XCJ0ZXh0LXhzIGZvbnQtc2VtaWJvbGQgbS0wIHRydW5jYXRlXCJcbiAgICAgICAgICAgIC8vIFRoZSBmdWxsIG11bHRpLWxpbmUgbWVzc2FnZSBpcyBpbiB0aGUgc3RhY2sgYm9keSBiZWxvdzsgdGhlXG4gICAgICAgICAgICAvLyBoZWFkZXIganVzdCBzaG93cyB0aGUgZmlyc3QgbGluZSwgc2luZ2xlLWxpbmUsIHdpdGggb3ZlcmZsb3dcbiAgICAgICAgICAgIC8vIGVsbGlwc2lzZWQgc28gYSBsb25nIHRpdGxlIGRvZXNuJ3QgcHVzaCB0aGUgY29weSBidXR0b24gb3JcbiAgICAgICAgICAgIC8vIHdyYXAgaW50byB0aGUgZnJhbWVkIGhpbnQvZG9jcyBsaW5lcy5cbiAgICAgICAgICAgIHRpdGxlPXttZXNzYWdlfVxuICAgICAgICAgID5cbiAgICAgICAgICAgIHt0aXRsZX1cbiAgICAgICAgICA8L3A+XG4gICAgICAgIDwvZGl2PlxuICAgICAgKX1cbiAgICAgIDxwcmVcbiAgICAgICAgY2xhc3NOYW1lPVwicHgtMyBweS0yLjUgdGV4dC14cyBmb250LW1vbm8gd2hpdGVzcGFjZS1wcmUtd3JhcCBicmVhay13b3JkcyBvdmVyZmxvdy1hdXRvIG0tMFwiXG4gICAgICAgIHN0eWxlPXt7XG4gICAgICAgICAgY29sb3I6ICd2YXIoLS1kcy1yZWQtOTAwKScsXG4gICAgICAgICAgYmFja2dyb3VuZDogJ3ZhcigtLWRzLXJlZC0yMDApJyxcbiAgICAgICAgfX1cbiAgICAgID5cbiAgICAgICAge3N0YWNrfVxuICAgICAgPC9wcmU+XG4gICAgPC9kaXY+XG4gICk7XG59XG4iXX0=
68
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3Itc3RhY2stYmxvY2suanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvY29tcG9uZW50cy91aS9lcnJvci1zdGFjay1ibG9jay50c3giXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsWUFBWSxDQUFDOztBQUViLE9BQU8sRUFBRSxXQUFXLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDM0MsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLDRDQUE0QyxDQUFDO0FBT3hFOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsaUJBQWlCLENBQy9CLEtBQWM7SUFFZCxPQUFPLENBQ0wsS0FBSyxJQUFJLElBQUk7UUFDYixPQUFPLEtBQUssS0FBSyxRQUFRO1FBQ3pCLENBQUMsT0FBUSxLQUFpQyxDQUFDLE9BQU8sS0FBSyxRQUFRO1lBQzdELE9BQVEsS0FBaUMsQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQ2hFLENBQUM7QUFDSixDQUFDO0FBRUQ7O0dBRUc7QUFDSCxNQUFNLFVBQVUsMEJBQTBCLENBQ3hDLEtBQWM7SUFFZCxPQUFPLENBQ0wsaUJBQWlCLENBQUMsS0FBSyxDQUFDO1FBQ3hCLE9BQVEsS0FBK0IsQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUMzRCxDQUFDO0FBQ0osQ0FBQztBQUVEOzs7Ozs7OztHQVFHO0FBQ0gsU0FBUyxXQUFXLENBQUMsT0FBZTtJQUNsQyxNQUFNLFNBQVMsR0FDYixPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsSUFBSSxPQUFPLENBQUM7SUFDeEUsT0FBTyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7QUFDMUIsQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsZUFBZSxDQUFDLEVBQUUsS0FBSyxFQUFvQztJQUN6RSxNQUFNLEtBQUssR0FBRyxPQUFPLEtBQUssQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7SUFDeEUsTUFBTSxPQUFPLEdBQUcsT0FBTyxLQUFLLENBQUMsT0FBTyxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQzlFLE1BQU0sSUFBSSxHQUFHLEtBQUssSUFBSSxPQUFPLElBQUksRUFBRSxDQUFDO0lBQ3BDLHVFQUF1RTtJQUN2RSx5RUFBeUU7SUFDekUsMkNBQTJDO0lBQzNDLE1BQU0sS0FBSyxHQUFHLE9BQU8sQ0FBQyxDQUFDLENBQUMsV0FBVyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDakUsTUFBTSxRQUFRLEdBQ1osT0FBTyxJQUFJLEtBQUssSUFBSSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUMsT0FBTyxDQUFDO1FBQzFDLENBQUMsQ0FBQyxHQUFHLE9BQU8sT0FBTyxLQUFLLEVBQUU7UUFDMUIsQ0FBQyxDQUFDLElBQUksQ0FBQztJQUVYLE9BQU8sQ0FDTCxlQUNFLFNBQVMsRUFBQyw0Q0FBNEMsRUFDdEQsS0FBSyxFQUFFO1lBQ0wsV0FBVyxFQUFFLG1CQUFtQjtZQUNoQyxVQUFVLEVBQUUsbUJBQW1CO1NBQ2hDLGFBRUQsS0FBQyxVQUFVLElBQ1QsUUFBUSxFQUFFLFFBQVEsRUFDbEIsU0FBUyxFQUFDLFlBQVksRUFDdEIsU0FBUyxFQUFDLG1OQUFtTixHQUM3TixFQUVELEtBQUssSUFBSSxDQUNSLGVBQ0UsU0FBUyxFQUFDLDJDQUEyQyxFQUNyRCxLQUFLLEVBQUU7b0JBQ0wsS0FBSyxFQUFFLG1CQUFtQjtvQkFDMUIsWUFBWSxFQUFFLDZCQUE2QjtpQkFDNUMsYUFFRCxLQUFDLFdBQVcsSUFBQyxTQUFTLEVBQUMsa0JBQWtCLEdBQUcsRUFDNUMsWUFDRSxTQUFTLEVBQUMsb0NBQW9DO3dCQUM5QyxrRUFBa0U7d0JBQ2xFLG1EQUFtRDt3QkFDbkQsNkRBQTZEO3dCQUM3RCx3Q0FBd0M7d0JBQ3hDLEtBQUssRUFBRSxPQUFPLFlBRWIsS0FBSyxHQUNKLElBQ0EsQ0FDUCxFQUNBLElBQUksSUFBSSxDQUNQLGNBQ0UsU0FBUyxFQUFDLGlGQUFpRixFQUMzRixLQUFLLEVBQUU7b0JBQ0wsS0FBSyxFQUFFLG1CQUFtQjtvQkFDMUIsVUFBVSxFQUFFLG1CQUFtQjtpQkFDaEMsWUFFQSxJQUFJLEdBQ0QsQ0FDUCxJQUNHLENBQ1AsQ0FBQztBQUNKLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIGNsaWVudCc7XG5cbmltcG9ydCB7IEFsZXJ0Q2lyY2xlIH0gZnJvbSAnbHVjaWRlLXJlYWN0JztcbmltcG9ydCB7IENvcHlCdXR0b24gfSBmcm9tICcuLi9uZXctdHJhY2Utdmlld2VyL2NvbXBvbmVudHMvY29weS1idXR0b24nO1xuXG5leHBvcnQgdHlwZSBTdHJ1Y3R1cmVkRXJyb3JSZWNvcmQgPSBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPiAmIHtcbiAgbWVzc2FnZT86IHN0cmluZztcbiAgc3RhY2s/OiBzdHJpbmc7XG59O1xuXG4vKipcbiAqIENoZWNrIHdoZXRoZXIgYHZhbHVlYCBsb29rcyBsaWtlIGEgc3RydWN0dXJlZCBlcnJvciBvYmplY3Qgd2UgY2FuIHJlbmRlclxuICogd2l0aCB0aGUgZXJyb3IgYmxvY2suIFNvbWUgcGVyc2lzdGVkIHdvcmtmbG93IGVycm9ycyBvbmx5IGluY2x1ZGUgYVxuICogYG1lc3NhZ2VgLCB3aGlsZSBydW50aW1lIGVycm9ycyB1c3VhbGx5IGFsc28gaW5jbHVkZSBgc3RhY2tgLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaXNTdHJ1Y3R1cmVkRXJyb3IoXG4gIHZhbHVlOiB1bmtub3duXG4pOiB2YWx1ZSBpcyBTdHJ1Y3R1cmVkRXJyb3JSZWNvcmQge1xuICByZXR1cm4gKFxuICAgIHZhbHVlICE9IG51bGwgJiZcbiAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmXG4gICAgKHR5cGVvZiAodmFsdWUgYXMgUmVjb3JkPHN0cmluZywgdW5rbm93bj4pLm1lc3NhZ2UgPT09ICdzdHJpbmcnIHx8XG4gICAgICB0eXBlb2YgKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5zdGFjayA9PT0gJ3N0cmluZycpXG4gICk7XG59XG5cbi8qKlxuICogTmFycm93ZXIgZ3VhcmQga2VwdCBmb3IgY2FsbGVycyB0aGF0IHNwZWNpZmljYWxseSBuZWVkIGEgc3RhY2sgdHJhY2UuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBpc1N0cnVjdHVyZWRFcnJvcldpdGhTdGFjayhcbiAgdmFsdWU6IHVua25vd25cbik6IHZhbHVlIGlzIFN0cnVjdHVyZWRFcnJvclJlY29yZCAmIHsgc3RhY2s6IHN0cmluZyB9IHtcbiAgcmV0dXJuIChcbiAgICBpc1N0cnVjdHVyZWRFcnJvcih2YWx1ZSkgJiZcbiAgICB0eXBlb2YgKHZhbHVlIGFzIFN0cnVjdHVyZWRFcnJvclJlY29yZCkuc3RhY2sgPT09ICdzdHJpbmcnXG4gICk7XG59XG5cbi8qKlxuICogUHVsbCBhIHNob3J0LCBzaW5nbGUtbGluZSB0aXRsZSBvdXQgb2YgYW4gZXJyb3IgbWVzc2FnZS5cbiAqXG4gKiBXb3JrZmxvdydzIHN0cnVjdHVyZWQgZXJyb3IgbWVzc2FnZXMgYXJlIG11bHRpLWxpbmUg4oCUIHRoZSBmaXJzdCBsaW5lIGlzXG4gKiB0aGUgaGVhZGxpbmUgKGBGYWlsZWQgdG8gc2VyaWFsaXplIHN0ZXAgcmV0dXJuIHZhbHVlYCkgYW5kIHRoZSByZXN0IGFyZVxuICogYOKVsOKWtiBoaW50OmAgLyBg4pWw4pa2IGRvY3M6YCBmcmFtZWQgZGV0YWlscy4gVGhlIGZ1bGwgbWVzc2FnZSBiZWxvbmdzIGluIHRoZVxuICogYm9keSBvZiB0aGUgZXJyb3IgYmxvY2s7IHRoZSB0aXRsZSBzaG91bGQganVzdCBiZSB0aGUgaGVhZGxpbmUgc28gdGhlXG4gKiBjYXJkIHN0YXlzIHNjYW5uYWJsZS5cbiAqL1xuZnVuY3Rpb24gZGVyaXZlVGl0bGUobWVzc2FnZTogc3RyaW5nKTogc3RyaW5nIHtcbiAgY29uc3QgZmlyc3RMaW5lID1cbiAgICBtZXNzYWdlLnNwbGl0KCdcXG4nKS5maW5kKChsaW5lKSA9PiBsaW5lLnRyaW0oKS5sZW5ndGggPiAwKSA/PyBtZXNzYWdlO1xuICByZXR1cm4gZmlyc3RMaW5lLnRyaW0oKTtcbn1cblxuLyoqXG4gKiBSZW5kZXJzIGEgc3RydWN0dXJlZCBlcnJvciBhcyBhIHZpc3VhbGx5IGRpc3RpbmN0IGVycm9yIGJsb2NrLiBTaG93cyB0aGVcbiAqIGVycm9yIG1lc3NhZ2Ugd2l0aCBhbiBhbGVydCBpY29uIGF0IHRoZSB0b3AsIHNlcGFyYXRlZCBmcm9tIHRoZSBzdGFjayB0cmFjZVxuICogb3IgZnVsbCBtZXNzYWdlIGJlbG93LlxuICovXG5leHBvcnQgZnVuY3Rpb24gRXJyb3JTdGFja0Jsb2NrKHsgdmFsdWUgfTogeyB2YWx1ZTogU3RydWN0dXJlZEVycm9yUmVjb3JkIH0pIHtcbiAgY29uc3Qgc3RhY2sgPSB0eXBlb2YgdmFsdWUuc3RhY2sgPT09ICdzdHJpbmcnID8gdmFsdWUuc3RhY2sgOiB1bmRlZmluZWQ7XG4gIGNvbnN0IG1lc3NhZ2UgPSB0eXBlb2YgdmFsdWUubWVzc2FnZSA9PT0gJ3N0cmluZycgPyB2YWx1ZS5tZXNzYWdlIDogdW5kZWZpbmVkO1xuICBjb25zdCBib2R5ID0gc3RhY2sgPz8gbWVzc2FnZSA/PyAnJztcbiAgLy8gVjgncyBgRXJyb3Iuc3RhY2tgIGFscmVhZHkgc3RhcnRzIHdpdGggYE5hbWU6IG1lc3NhZ2VgOyBtZXNzYWdlLW9ubHlcbiAgLy8gZXJyb3JzIHVzZSB0aGUgbWVzc2FnZSBhcyB0aGUgYm9keSBzbyBsb25nIHNpbmdsZS1saW5lIGZhaWx1cmVzIHJlbWFpblxuICAvLyByZWFkYWJsZSBldmVuIHdoZW4gdGhlIGhlYWRlciB0cnVuY2F0ZXMuXG4gIGNvbnN0IHRpdGxlID0gbWVzc2FnZSA/IGRlcml2ZVRpdGxlKG1lc3NhZ2UpIDogZGVyaXZlVGl0bGUoYm9keSk7XG4gIGNvbnN0IGNvcHlUZXh0ID1cbiAgICBtZXNzYWdlICYmIHN0YWNrICYmICFzdGFjay5pbmNsdWRlcyhtZXNzYWdlKVxuICAgICAgPyBgJHttZXNzYWdlfVxcblxcbiR7c3RhY2t9YFxuICAgICAgOiBib2R5O1xuXG4gIHJldHVybiAoXG4gICAgPGRpdlxuICAgICAgY2xhc3NOYW1lPVwicmVsYXRpdmUgb3ZlcmZsb3ctaGlkZGVuIHJvdW5kZWQtbWQgYm9yZGVyXCJcbiAgICAgIHN0eWxlPXt7XG4gICAgICAgIGJvcmRlckNvbG9yOiAndmFyKC0tZHMtcmVkLTQwMCknLFxuICAgICAgICBiYWNrZ3JvdW5kOiAndmFyKC0tZHMtcmVkLTEwMCknLFxuICAgICAgfX1cbiAgICA+XG4gICAgICA8Q29weUJ1dHRvblxuICAgICAgICBjb3B5VGV4dD17Y29weVRleHR9XG4gICAgICAgIGFyaWFMYWJlbD1cIkNvcHkgZXJyb3JcIlxuICAgICAgICBjbGFzc05hbWU9XCJhYnNvbHV0ZSByaWdodC0yIHRvcC0yIGZsZXggaC02IHctNiBpdGVtcy1jZW50ZXIganVzdGlmeS1jZW50ZXIgcm91bmRlZC1tZCBib3JkZXIgYm9yZGVyLXJlZC00MDAgYmctcmVkLTEwMCBwLTAgdGV4dC1yZWQtOTAwIHRyYW5zaXRpb24tdHJhbnNmb3JtIHRyYW5zaXRpb24tY29sb3JzIGR1cmF0aW9uLTEwMCBob3ZlcjpiZy1yZWQtMjAwIGFjdGl2ZTpzY2FsZS05NVwiXG4gICAgICAvPlxuXG4gICAgICB7dGl0bGUgJiYgKFxuICAgICAgICA8ZGl2XG4gICAgICAgICAgY2xhc3NOYW1lPVwiZmxleCBpdGVtcy1jZW50ZXIgZ2FwLTIgcHgtMyBweS0yLjUgcHItMTBcIlxuICAgICAgICAgIHN0eWxlPXt7XG4gICAgICAgICAgICBjb2xvcjogJ3ZhcigtLWRzLXJlZC05MDApJyxcbiAgICAgICAgICAgIGJvcmRlckJvdHRvbTogJzFweCBzb2xpZCB2YXIoLS1kcy1yZWQtNDAwKScsXG4gICAgICAgICAgfX1cbiAgICAgICAgPlxuICAgICAgICAgIDxBbGVydENpcmNsZSBjbGFzc05hbWU9XCJoLTQgdy00IHNocmluay0wXCIgLz5cbiAgICAgICAgICA8cFxuICAgICAgICAgICAgY2xhc3NOYW1lPVwidGV4dC14cyBmb250LXNlbWlib2xkIG0tMCB0cnVuY2F0ZVwiXG4gICAgICAgICAgICAvLyBUaGUgZnVsbCBtZXNzYWdlIG9yIHN0YWNrIGlzIGluIHRoZSBib2R5IGJlbG93OyB0aGUgaGVhZGVyIGp1c3RcbiAgICAgICAgICAgIC8vIHNob3dzIHRoZSBmaXJzdCBsaW5lLCBzaW5nbGUtbGluZSwgd2l0aCBvdmVyZmxvd1xuICAgICAgICAgICAgLy8gZWxsaXBzaXNlZCBzbyBhIGxvbmcgdGl0bGUgZG9lc24ndCBwdXNoIHRoZSBjb3B5IGJ1dHRvbiBvclxuICAgICAgICAgICAgLy8gd3JhcCBpbnRvIHRoZSBmcmFtZWQgaGludC9kb2NzIGxpbmVzLlxuICAgICAgICAgICAgdGl0bGU9e21lc3NhZ2V9XG4gICAgICAgICAgPlxuICAgICAgICAgICAge3RpdGxlfVxuICAgICAgICAgIDwvcD5cbiAgICAgICAgPC9kaXY+XG4gICAgICApfVxuICAgICAge2JvZHkgJiYgKFxuICAgICAgICA8cHJlXG4gICAgICAgICAgY2xhc3NOYW1lPVwicHgtMyBweS0yLjUgdGV4dC14cyBmb250LW1vbm8gd2hpdGVzcGFjZS1wcmUtd3JhcCBicmVhay13b3JkcyBvdmVyZmxvdy1hdXRvIG0tMFwiXG4gICAgICAgICAgc3R5bGU9e3tcbiAgICAgICAgICAgIGNvbG9yOiAndmFyKC0tZHMtcmVkLTkwMCknLFxuICAgICAgICAgICAgYmFja2dyb3VuZDogJ3ZhcigtLWRzLXJlZC0yMDApJyxcbiAgICAgICAgICB9fVxuICAgICAgICA+XG4gICAgICAgICAge2JvZHl9XG4gICAgICAgIDwvcHJlPlxuICAgICAgKX1cbiAgICA8L2Rpdj5cbiAgKTtcbn1cbiJdfQ==
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@workflow/web-shared",
3
3
  "description": "Shared components for Workflow Observability UI",
4
- "version": "5.0.0-beta.12",
4
+ "version": "5.0.0-beta.13",
5
5
  "private": false,
6
6
  "files": [
7
7
  "dist",
@@ -53,7 +53,7 @@
53
53
  "streamdown": "2.3.0",
54
54
  "tailwind-merge": "3.5.0",
55
55
  "tailwindcss": "4",
56
- "@workflow/core": "5.0.0-beta.12",
56
+ "@workflow/core": "5.0.0-beta.13",
57
57
  "@workflow/utils": "5.0.0-beta.3",
58
58
  "@workflow/world": "5.0.0-beta.7"
59
59
  },
@@ -10,20 +10,21 @@ import type {
10
10
  } from 'react';
11
11
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
12
12
  import { Virtuoso, type VirtuosoHandle } from 'react-virtuoso';
13
- import { isEncryptedMarker } from '../lib/hydration';
14
13
  import {
15
- parseExactWorkflowSearchId,
16
- looksLikeWorkflowIdSearchInput,
17
14
  type ExactIdSearchResult,
18
15
  type ExactWorkflowSearchIdKind,
16
+ looksLikeWorkflowIdSearchInput,
17
+ parseExactWorkflowSearchId,
19
18
  } from '../lib/exact-event-search-id';
20
- import { DecryptButton } from './ui/decrypt-button';
21
- import { formatDuration } from '../lib/utils';
19
+ import { isEncryptedMarker } from '../lib/hydration';
22
20
  import { useToast } from '../lib/toast';
21
+ import { formatDuration } from '../lib/utils';
23
22
  import { DataInspector, DecryptClickContext } from './ui/data-inspector';
23
+ import { DecryptButton } from './ui/decrypt-button';
24
24
  import {
25
25
  ErrorStackBlock,
26
- isStructuredErrorWithStack,
26
+ isStructuredError,
27
+ type StructuredErrorRecord,
27
28
  } from './ui/error-stack-block';
28
29
  import { LoadMoreButton } from './ui/load-more-button';
29
30
  import { MenuDropdown } from './ui/menu-dropdown';
@@ -519,20 +520,20 @@ function deepParseJson(value: unknown): unknown {
519
520
  }
520
521
 
521
522
  /**
522
- * Extracts a structured error with a stack trace from event data, if present.
523
+ * Extracts a structured error from event data, if present.
523
524
  * Returns the error object to render with ErrorStackBlock, or null if not applicable.
524
525
  */
525
526
  function extractStructuredError(
526
527
  data: unknown,
527
528
  eventType?: string
528
- ): (Record<string, unknown> & { stack: string }) | null {
529
+ ): StructuredErrorRecord | null {
529
530
  if (!eventType || !ERROR_EVENT_TYPES.has(eventType)) return null;
530
531
  if (data == null || typeof data !== 'object') return null;
531
532
  const record = data as Record<string, unknown>;
532
533
  // Check the nested `error` field first (the StructuredError)
533
- if (isStructuredErrorWithStack(record.error)) return record.error;
534
- // Some error formats put the stack at the top level of eventData
535
- if (isStructuredErrorWithStack(record)) return record;
534
+ if (isStructuredError(record.error)) return record.error;
535
+ // Some error formats put the message/stack at the top level of eventData.
536
+ if (isStructuredError(record)) return record;
536
537
  return null;
537
538
  }
538
539
 
@@ -1,7 +1,7 @@
1
1
  import { Circle } from 'lucide-react';
2
2
  import { useRef } from 'react';
3
3
  import { cn } from '../../../lib/utils';
4
- import type { Span } from '../../trace-viewer/types';
4
+ import type { Span } from '../types';
5
5
  import { formatDuration } from '../../trace-viewer/util/timing';
6
6
  import {
7
7
  SleepIcon,
@@ -53,8 +53,9 @@ const EventRow = ({
53
53
  onSelectSpan: (spanId: string) => void;
54
54
  }) => {
55
55
  const durationMs = getSpanDurationMs(span);
56
- const isErrored =
57
- (span.attributes.data as Record<string, unknown>).status === 'failed';
56
+ const workflowStatus = (span.attributes.data as Record<string, unknown>)
57
+ ?.status as string | undefined;
58
+ const isErrored = span.status.code === 2 || workflowStatus === 'failed';
58
59
  const { icon: Icon, className: tagClassName } = getEventStyle(
59
60
  span.resource,
60
61
  isErrored
@@ -4,7 +4,7 @@ import { ArrowLeft, ArrowRight } from 'lucide-react';
4
4
  import type { CSSProperties, ReactNode } from 'react';
5
5
  import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
6
6
  import { cn } from '../../../lib/utils';
7
- import type { Span } from '../../trace-viewer/types';
7
+ import type { Span } from '../types';
8
8
  import { formatDuration, getHighResInMs } from '../../trace-viewer/util/timing';
9
9
  import { isSpanDimmedBySearch, type SpanSearchResult } from '../search';
10
10
  import type { Segment, SegmentStatus, TimeMarker } from '../utils';
@@ -234,7 +234,7 @@ function SegmentBar({ segments }: { segments: VisibleSegment[] }): ReactNode {
234
234
 
235
235
  return (
236
236
  <div
237
- key={`${seg.status}-${i}`}
237
+ key={i}
238
238
  className={cn(
239
239
  'absolute h-full rounded-[0.25rem]',
240
240
  SEGMENT_CLASSES[seg.status]
@@ -421,7 +421,7 @@ export function TimelineHeader({
421
421
  <div className="relative h-full flex-1">
422
422
  {markers.map((m) => (
423
423
  <span
424
- key={`${m.position}-${m.label}`}
424
+ key={String(m.value)}
425
425
  className="absolute bottom-1 font-mono text-xs font-normal leading-4 text-gray-900 whitespace-nowrap"
426
426
  style={{ left: `${m.position * 100}%` }}
427
427
  >
@@ -506,7 +506,7 @@ export function Timeline({
506
506
  // Skip the "0s" origin marker since the left edge already implies it.
507
507
  Math.abs(marker.value) > 0.000001 ? (
508
508
  <div
509
- key={`${marker.position}-${marker.label}`}
509
+ key={String(marker.value)}
510
510
  className="absolute top-0 bottom-0 w-px bg-gray-alpha-300"
511
511
  style={{ left: `${marker.position * 100}%` }}
512
512
  />
@@ -9,7 +9,7 @@ import {
9
9
  useMemo,
10
10
  useState,
11
11
  } from 'react';
12
- import type { Span } from '../trace-viewer/types';
12
+ import type { Span } from './types';
13
13
 
14
14
  interface ActiveSpanContextValue {
15
15
  activeSpanId: string | null;
@@ -3,7 +3,7 @@ const WorkflowIcon = () => {
3
3
  <svg
4
4
  data-testid="geist-icon"
5
5
  height="16"
6
- stroke-linejoin="round"
6
+ strokeLinejoin="round"
7
7
  style={{ color: 'currentColor' }}
8
8
  viewBox="0 0 16 16"
9
9
  width="16"
@@ -21,7 +21,7 @@ const WebhookIcon = () => {
21
21
  <svg
22
22
  data-testid="geist-icon"
23
23
  height="16"
24
- stroke-linejoin="round"
24
+ strokeLinejoin="round"
25
25
  viewBox="0 0 16 16"
26
26
  width="16"
27
27
  style={{ color: 'currentColor' }}
@@ -1,4 +1,4 @@
1
- import type { Span } from '../trace-viewer/types';
1
+ import type { Span } from './types';
2
2
 
3
3
  const ATTR_FILTER_REGEX = /(?:^|\s)(?<pair>(?<key>[\w.]+):(?<value>\S*))/g;
4
4
 
@@ -26,8 +26,8 @@ import {
26
26
  EntityDetailPanel,
27
27
  type SelectedSpanInfo,
28
28
  } from '../sidebar/entity-detail-panel';
29
- import { useSidebarDataOptional } from '../sidebar/sidebar-data-context';
30
- import type { Trace } from '../trace-viewer/types';
29
+ import { useSidebarData } from '../sidebar/sidebar-data-context';
30
+ import type { TraceWithMeta } from './types';
31
31
  import { formatDuration, getHighResInMs } from '../trace-viewer/util/timing';
32
32
  import { IconButton } from '../ui/icon-button';
33
33
  import { Spinner } from '../ui/spinner';
@@ -46,12 +46,11 @@ import {
46
46
  TooltipTrigger,
47
47
  } from '../ui/tooltip';
48
48
  import { ActiveSpanProvider, useActiveSpan } from './context';
49
- import { DetailPanel } from './detail-panel';
50
49
  import { searchSpans } from './search';
51
50
  import { computeRootBounds, computeTimeMarkers } from './utils';
52
51
 
53
52
  interface NewTraceViewerProps {
54
- trace: Trace;
53
+ trace: TraceWithMeta;
55
54
  onLoadMore?: () => void | Promise<void>;
56
55
  hasMore?: boolean;
57
56
  isLoadingMore?: boolean;
@@ -141,10 +140,10 @@ function useAnimatedViewport(initial: Viewport) {
141
140
 
142
141
  function useSelectedSpanInfo(): SelectedSpanInfo | null {
143
142
  const { activeSpan } = useActiveSpan();
144
- const sidebar = useSidebarDataOptional();
143
+ const sidebar = useSidebarData();
145
144
 
146
145
  return useMemo(() => {
147
- if (!activeSpan || !sidebar) return null;
146
+ if (!activeSpan) return null;
148
147
 
149
148
  const correlationId = activeSpan.spanId;
150
149
  const rawEvents = correlationId
@@ -193,7 +192,7 @@ function NewTraceViewerContent({
193
192
  const { activeSpan, activeSpanId, setActiveSpan, clearActiveSpan } =
194
193
  useActiveSpan();
195
194
 
196
- const sidebar = useSidebarDataOptional();
195
+ const sidebar = useSidebarData();
197
196
  const selectedSpan = useSelectedSpanInfo();
198
197
 
199
198
  const [searchQuery, setSearchQuery] = useState('');
@@ -674,7 +673,7 @@ function NewTraceViewerContent({
674
673
  </div>
675
674
 
676
675
  {/* Detail panel */}
677
- {activeSpan && sidebar ? (
676
+ {activeSpan ? (
678
677
  <aside className="flex flex-col h-full max-h-full bg-background-100 border-l border-gray-alpha-400 overflow-auto">
679
678
  {/* Panel header */}
680
679
  <div className="flex items-center justify-between gap-2 shrink-0 px-4 pt-3 pb-3">
@@ -750,12 +749,6 @@ function NewTraceViewerContent({
750
749
  </ErrorBoundary>
751
750
  </div>
752
751
  </aside>
753
- ) : activeSpan ? (
754
- <DetailPanel
755
- span={activeSpan}
756
- rootStart={root.startTime}
757
- onClose={clearActiveSpan}
758
- />
759
752
  ) : null}
760
753
  </div>
761
754
  );
@@ -0,0 +1,2 @@
1
+ export type { Span, SpanEvent, Trace } from '../trace-viewer/types';
2
+ export type { TraceWithMeta } from '../../lib/trace-builder';
@@ -1,4 +1,4 @@
1
- import type { Span, SpanEvent } from '../trace-viewer/types';
1
+ import type { Span, SpanEvent } from './types';
2
2
  import { formatDuration, getHighResInMs } from '../trace-viewer/util/timing';
3
3
 
4
4
  // ---------------------------------------------------------------------------
@@ -8,20 +8,17 @@ import { useCallback, useContext, useMemo, useState } from 'react';
8
8
  import { isEncryptedMarker, isExpiredMarker } from '../../lib/hydration';
9
9
  import { useToast } from '../../lib/toast';
10
10
  import { extractConversation, isDoStreamStep } from '../../lib/utils';
11
+ import { CopyButton } from '../new-trace-viewer/components/copy-button';
12
+ import { MiddleTruncate } from '../new-trace-viewer/components/middle-truncate/middle-truncate';
11
13
  import {
12
14
  DecryptClickContext,
13
15
  RunClickContext,
14
16
  StreamClickContext,
15
17
  } from '../ui/data-inspector';
16
18
  import { ErrorCard } from '../ui/error-card';
17
- import {
18
- ErrorStackBlock,
19
- isStructuredErrorWithStack,
20
- } from '../ui/error-stack-block';
19
+ import { ErrorStackBlock, isStructuredError } from '../ui/error-stack-block';
21
20
  import { Skeleton } from '../ui/skeleton';
22
21
  import { TimestampTooltip } from '../ui/timestamp-tooltip';
23
- import { CopyButton } from '../new-trace-viewer/components/copy-button';
24
- import { MiddleTruncate } from '../new-trace-viewer/components/middle-truncate/middle-truncate';
25
22
  import { ConversationView } from './conversation-view';
26
23
  import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
27
24
  import { DetailCard } from './detail-card';
@@ -548,9 +545,9 @@ const attributeToDisplayFn: Record<
548
545
  if (isExpiredMarker(value)) return <ExpiredFieldBlock />;
549
546
  if (!hasDisplayContent(value)) return null;
550
547
 
551
- // If the error object has a `stack` field, render it as readable
552
- // pre-formatted text. Otherwise fall back to the raw JSON viewer.
553
- if (isStructuredErrorWithStack(value)) {
548
+ // Structured workflow errors may be persisted as either `{ message }` or
549
+ // `{ message, stack }`. Render both with the dedicated error block.
550
+ if (isStructuredError(value)) {
554
551
  return (
555
552
  <DetailCard summary="Error" defaultOpen>
556
553
  <ErrorStackBlock value={value} />
@@ -4,10 +4,7 @@ import { EVENT_DATA_REF_FIELDS, type Event } from '@workflow/world';
4
4
  import { useCallback, useLayoutEffect, useMemo, useRef, useState } from 'react';
5
5
  import { hasEncryptedFields, isExpiredMarker } from '../../lib/hydration';
6
6
  import { ErrorCard } from '../ui/error-card';
7
- import {
8
- ErrorStackBlock,
9
- isStructuredErrorWithStack,
10
- } from '../ui/error-stack-block';
7
+ import { ErrorStackBlock, isStructuredError } from '../ui/error-stack-block';
11
8
  import { Skeleton } from '../ui/skeleton';
12
9
  import { CopyableDataBlock, EncryptedDataBlock } from './copyable-data-block';
13
10
  import { DetailCard } from './detail-card';
@@ -196,8 +193,8 @@ function hasOnlyExpiredFields(data: unknown, eventType: string): boolean {
196
193
  }
197
194
 
198
195
  /**
199
- * Renders event data, using ErrorStackBlock for error events that contain
200
- * a structured error with a stack trace, and CopyableDataBlock otherwise.
196
+ * Renders event data, using ErrorStackBlock for error events that contain a
197
+ * structured error, and CopyableDataBlock otherwise.
201
198
  */
202
199
  function EventDataBlock({
203
200
  eventType,
@@ -239,12 +236,12 @@ function EventDataBlock({
239
236
  const record = data as Record<string, unknown>;
240
237
 
241
238
  // Check the nested `error` field first (the StructuredError)
242
- if (isStructuredErrorWithStack(record.error)) {
239
+ if (isStructuredError(record.error)) {
243
240
  return <ErrorStackBlock value={record.error} />;
244
241
  }
245
242
 
246
- // Some error formats put the stack at the top level of eventData
247
- if (isStructuredErrorWithStack(record)) {
243
+ // Some error formats put the message/stack at the top level of eventData.
244
+ if (isStructuredError(record)) {
248
245
  return <ErrorStackBlock value={record} />;
249
246
  }
250
247
  }
@@ -8,7 +8,6 @@ import {
8
8
  type SidebarDataContextValue,
9
9
  SidebarDataProvider,
10
10
  } from './sidebar/sidebar-data-context';
11
- import type { Trace } from './trace-viewer/types';
12
11
 
13
12
  const NewTraceViewer = ({
14
13
  run,
@@ -27,14 +26,13 @@ const NewTraceViewer = ({
27
26
  isLoadingMore?: boolean;
28
27
  loading?: boolean;
29
28
  }) => {
30
- const traceWithMeta: TraceWithMeta | undefined = useMemo(() => {
29
+ const trace: TraceWithMeta | undefined = useMemo(() => {
31
30
  if (!run?.runId) {
32
31
  return undefined;
33
32
  }
34
33
  return buildTrace(run, events, new Date());
35
34
  // eslint-disable-next-line react-hooks/exhaustive-deps -- `new Date()` is intentionally not a dep
36
35
  }, [run, events]);
37
- const trace = traceWithMeta;
38
36
 
39
37
  if (!trace || (loading && events.length === 0)) {
40
38
  return <TraceViewerSkeleton />;
@@ -44,7 +42,7 @@ const NewTraceViewer = ({
44
42
  <SidebarDataProvider value={sidebarData}>
45
43
  <div className="relative w-full h-full flex">
46
44
  <NewTraceViewerComponent
47
- trace={trace as Trace}
45
+ trace={trace}
48
46
  onLoadMore={onLoadMore}
49
47
  hasMore={hasMore}
50
48
  isLoadingMore={isLoadingMore}
@@ -3,18 +3,36 @@
3
3
  import { AlertCircle } from 'lucide-react';
4
4
  import { CopyButton } from '../new-trace-viewer/components/copy-button';
5
5
 
6
+ export type StructuredErrorRecord = Record<string, unknown> & {
7
+ message?: string;
8
+ stack?: string;
9
+ };
10
+
6
11
  /**
7
- * Check whether `value` looks like a structured error object with a `stack`
8
- * field that we can render as pre-formatted text.
12
+ * Check whether `value` looks like a structured error object we can render
13
+ * with the error block. Some persisted workflow errors only include a
14
+ * `message`, while runtime errors usually also include `stack`.
9
15
  */
10
- export function isStructuredErrorWithStack(
16
+ export function isStructuredError(
11
17
  value: unknown
12
- ): value is Record<string, unknown> & { stack: string } {
18
+ ): value is StructuredErrorRecord {
13
19
  return (
14
20
  value != null &&
15
21
  typeof value === 'object' &&
16
- 'stack' in value &&
17
- typeof (value as Record<string, unknown>).stack === 'string'
22
+ (typeof (value as Record<string, unknown>).message === 'string' ||
23
+ typeof (value as Record<string, unknown>).stack === 'string')
24
+ );
25
+ }
26
+
27
+ /**
28
+ * Narrower guard kept for callers that specifically need a stack trace.
29
+ */
30
+ export function isStructuredErrorWithStack(
31
+ value: unknown
32
+ ): value is StructuredErrorRecord & { stack: string } {
33
+ return (
34
+ isStructuredError(value) &&
35
+ typeof (value as StructuredErrorRecord).stack === 'string'
18
36
  );
19
37
  }
20
38
 
@@ -34,22 +52,22 @@ function deriveTitle(message: string): string {
34
52
  }
35
53
 
36
54
  /**
37
- * Renders an error with a `stack` field as a visually distinct error block.
38
- * Shows the error message with an alert icon at the top, separated from
39
- * the stack trace below.
55
+ * Renders a structured error as a visually distinct error block. Shows the
56
+ * error message with an alert icon at the top, separated from the stack trace
57
+ * or full message below.
40
58
  */
41
- export function ErrorStackBlock({
42
- value,
43
- }: {
44
- value: Record<string, unknown> & { stack: string };
45
- }) {
46
- const stack = value.stack;
59
+ export function ErrorStackBlock({ value }: { value: StructuredErrorRecord }) {
60
+ const stack = typeof value.stack === 'string' ? value.stack : undefined;
47
61
  const message = typeof value.message === 'string' ? value.message : undefined;
48
- // V8's `Error.stack` already starts with `Name: message`, so when the
49
- // body shows the stack it includes the full multi-line message anyway.
50
- // The header just needs the first line.
51
- const title = message ? deriveTitle(message) : undefined;
52
- const copyText = message ? `${message}\n\n${stack}` : stack;
62
+ const body = stack ?? message ?? '';
63
+ // V8's `Error.stack` already starts with `Name: message`; message-only
64
+ // errors use the message as the body so long single-line failures remain
65
+ // readable even when the header truncates.
66
+ const title = message ? deriveTitle(message) : deriveTitle(body);
67
+ const copyText =
68
+ message && stack && !stack.includes(message)
69
+ ? `${message}\n\n${stack}`
70
+ : body;
53
71
 
54
72
  return (
55
73
  <div
@@ -76,8 +94,8 @@ export function ErrorStackBlock({
76
94
  <AlertCircle className="h-4 w-4 shrink-0" />
77
95
  <p
78
96
  className="text-xs font-semibold m-0 truncate"
79
- // The full multi-line message is in the stack body below; the
80
- // header just shows the first line, single-line, with overflow
97
+ // The full message or stack is in the body below; the header just
98
+ // shows the first line, single-line, with overflow
81
99
  // ellipsised so a long title doesn't push the copy button or
82
100
  // wrap into the framed hint/docs lines.
83
101
  title={message}
@@ -86,15 +104,17 @@ export function ErrorStackBlock({
86
104
  </p>
87
105
  </div>
88
106
  )}
89
- <pre
90
- className="px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0"
91
- style={{
92
- color: 'var(--ds-red-900)',
93
- background: 'var(--ds-red-200)',
94
- }}
95
- >
96
- {stack}
97
- </pre>
107
+ {body && (
108
+ <pre
109
+ className="px-3 py-2.5 text-xs font-mono whitespace-pre-wrap break-words overflow-auto m-0"
110
+ style={{
111
+ color: 'var(--ds-red-900)',
112
+ background: 'var(--ds-red-200)',
113
+ }}
114
+ >
115
+ {body}
116
+ </pre>
117
+ )}
98
118
  </div>
99
119
  );
100
120
  }
@@ -1,10 +0,0 @@
1
- import type { ReactNode } from 'react';
2
- import type { Span } from '../trace-viewer/types';
3
- interface DetailPanelProps {
4
- span: Span;
5
- rootStart: number;
6
- onClose: () => void;
7
- }
8
- export declare function DetailPanel({ span, rootStart, onClose, }: DetailPanelProps): ReactNode;
9
- export {};
10
- //# sourceMappingURL=detail-panel.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"detail-panel.d.ts","sourceRoot":"","sources":["../../../src/components/new-trace-viewer/detail-panel.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,uBAAuB,CAAC;AAKlD,UAAU,gBAAgB;IACxB,IAAI,EAAE,IAAI,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,SAAS,EACT,OAAO,GACR,EAAE,gBAAgB,GAAG,SAAS,CAmC9B"}
@@ -1,13 +0,0 @@
1
- 'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import { X } from 'lucide-react';
4
- import { formatDuration, getHighResInMs } from '../trace-viewer/util/timing';
5
- import { IconButton } from '../ui/icon-button';
6
- import { getSpanDurationMs } from './utils';
7
- export function DetailPanel({ span, rootStart, onClose, }) {
8
- const startMs = getHighResInMs(span.startTime);
9
- const durationMs = getSpanDurationMs(span);
10
- const offsetMs = startMs - rootStart;
11
- return (_jsxs("aside", { className: "grid h-full max-h-full grid-rows-[2.5rem_1fr] bg-background-200", children: [_jsxs("div", { className: "flex items-center justify-between px-3 border-b border-gray-alpha-400", children: [_jsx("span", { className: "text-sm font-medium text-gray-1000 truncate", children: span.name }), _jsx(IconButton, { "aria-label": "Close span details", onClick: onClose, children: _jsx(X, { className: "w-4 h-4" }) })] }), _jsx("div", { className: "overflow-y-auto p-3 space-y-3", children: _jsxs("dl", { className: "grid grid-cols-[auto_1fr] gap-x-3 gap-y-1.5 text-sm", children: [_jsx("dt", { className: "text-gray-900", children: "Resource" }), _jsx("dd", { className: "text-gray-1000 font-mono", children: span.resource }), _jsx("dt", { className: "text-gray-900", children: "Duration" }), _jsx("dd", { className: "text-gray-1000 tabular-nums font-mono", children: formatDuration(durationMs) }), _jsx("dt", { className: "text-gray-900", children: "Offset" }), _jsxs("dd", { className: "text-gray-1000 tabular-nums font-mono", children: ["+", formatDuration(offsetMs)] }), _jsx("dt", { className: "text-gray-900", children: "Status" }), _jsx("dd", { className: "text-gray-1000 font-mono", children: span.status.code === 2 ? 'Error' : 'OK' })] }) })] }));
12
- }
13
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZGV0YWlsLXBhbmVsLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL2NvbXBvbmVudHMvbmV3LXRyYWNlLXZpZXdlci9kZXRhaWwtcGFuZWwudHN4Il0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLFlBQVksQ0FBQzs7QUFFYixPQUFPLEVBQUUsQ0FBQyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBR2pDLE9BQU8sRUFBRSxjQUFjLEVBQUUsY0FBYyxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDN0UsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQy9DLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLFNBQVMsQ0FBQztBQVE1QyxNQUFNLFVBQVUsV0FBVyxDQUFDLEVBQzFCLElBQUksRUFDSixTQUFTLEVBQ1QsT0FBTyxHQUNVO0lBQ2pCLE1BQU0sT0FBTyxHQUFHLGNBQWMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDL0MsTUFBTSxVQUFVLEdBQUcsaUJBQWlCLENBQUMsSUFBSSxDQUFDLENBQUM7SUFDM0MsTUFBTSxRQUFRLEdBQUcsT0FBTyxHQUFHLFNBQVMsQ0FBQztJQUVyQyxPQUFPLENBQ0wsaUJBQU8sU0FBUyxFQUFDLGlFQUFpRSxhQUNoRixlQUFLLFNBQVMsRUFBQyx1RUFBdUUsYUFDcEYsZUFBTSxTQUFTLEVBQUMsNkNBQTZDLFlBQzFELElBQUksQ0FBQyxJQUFJLEdBQ0wsRUFDUCxLQUFDLFVBQVUsa0JBQVksb0JBQW9CLEVBQUMsT0FBTyxFQUFFLE9BQU8sWUFDMUQsS0FBQyxDQUFDLElBQUMsU0FBUyxFQUFDLFNBQVMsR0FBRyxHQUNkLElBQ1QsRUFDTixjQUFLLFNBQVMsRUFBQywrQkFBK0IsWUFDNUMsY0FBSSxTQUFTLEVBQUMscURBQXFELGFBQ2pFLGFBQUksU0FBUyxFQUFDLGVBQWUseUJBQWMsRUFDM0MsYUFBSSxTQUFTLEVBQUMsMEJBQTBCLFlBQUUsSUFBSSxDQUFDLFFBQVEsR0FBTSxFQUM3RCxhQUFJLFNBQVMsRUFBQyxlQUFlLHlCQUFjLEVBQzNDLGFBQUksU0FBUyxFQUFDLHVDQUF1QyxZQUNsRCxjQUFjLENBQUMsVUFBVSxDQUFDLEdBQ3hCLEVBQ0wsYUFBSSxTQUFTLEVBQUMsZUFBZSx1QkFBWSxFQUN6QyxjQUFJLFNBQVMsRUFBQyx1Q0FBdUMsa0JBQ2pELGNBQWMsQ0FBQyxRQUFRLENBQUMsSUFDdkIsRUFDTCxhQUFJLFNBQVMsRUFBQyxlQUFlLHVCQUFZLEVBQ3pDLGFBQUksU0FBUyxFQUFDLDBCQUEwQixZQUNyQyxJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsSUFBSSxHQUNyQyxJQUNGLEdBQ0QsSUFDQSxDQUNULENBQUM7QUFDSixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBjbGllbnQnO1xuXG5pbXBvcnQgeyBYIH0gZnJvbSAnbHVjaWRlLXJlYWN0JztcbmltcG9ydCB0eXBlIHsgUmVhY3ROb2RlIH0gZnJvbSAncmVhY3QnO1xuaW1wb3J0IHR5cGUgeyBTcGFuIH0gZnJvbSAnLi4vdHJhY2Utdmlld2VyL3R5cGVzJztcbmltcG9ydCB7IGZvcm1hdER1cmF0aW9uLCBnZXRIaWdoUmVzSW5NcyB9IGZyb20gJy4uL3RyYWNlLXZpZXdlci91dGlsL3RpbWluZyc7XG5pbXBvcnQgeyBJY29uQnV0dG9uIH0gZnJvbSAnLi4vdWkvaWNvbi1idXR0b24nO1xuaW1wb3J0IHsgZ2V0U3BhbkR1cmF0aW9uTXMgfSBmcm9tICcuL3V0aWxzJztcblxuaW50ZXJmYWNlIERldGFpbFBhbmVsUHJvcHMge1xuICBzcGFuOiBTcGFuO1xuICByb290U3RhcnQ6IG51bWJlcjtcbiAgb25DbG9zZTogKCkgPT4gdm9pZDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIERldGFpbFBhbmVsKHtcbiAgc3BhbixcbiAgcm9vdFN0YXJ0LFxuICBvbkNsb3NlLFxufTogRGV0YWlsUGFuZWxQcm9wcyk6IFJlYWN0Tm9kZSB7XG4gIGNvbnN0IHN0YXJ0TXMgPSBnZXRIaWdoUmVzSW5NcyhzcGFuLnN0YXJ0VGltZSk7XG4gIGNvbnN0IGR1cmF0aW9uTXMgPSBnZXRTcGFuRHVyYXRpb25NcyhzcGFuKTtcbiAgY29uc3Qgb2Zmc2V0TXMgPSBzdGFydE1zIC0gcm9vdFN0YXJ0O1xuXG4gIHJldHVybiAoXG4gICAgPGFzaWRlIGNsYXNzTmFtZT1cImdyaWQgaC1mdWxsIG1heC1oLWZ1bGwgZ3JpZC1yb3dzLVsyLjVyZW1fMWZyXSBiZy1iYWNrZ3JvdW5kLTIwMFwiPlxuICAgICAgPGRpdiBjbGFzc05hbWU9XCJmbGV4IGl0ZW1zLWNlbnRlciBqdXN0aWZ5LWJldHdlZW4gcHgtMyBib3JkZXItYiBib3JkZXItZ3JheS1hbHBoYS00MDBcIj5cbiAgICAgICAgPHNwYW4gY2xhc3NOYW1lPVwidGV4dC1zbSBmb250LW1lZGl1bSB0ZXh0LWdyYXktMTAwMCB0cnVuY2F0ZVwiPlxuICAgICAgICAgIHtzcGFuLm5hbWV9XG4gICAgICAgIDwvc3Bhbj5cbiAgICAgICAgPEljb25CdXR0b24gYXJpYS1sYWJlbD1cIkNsb3NlIHNwYW4gZGV0YWlsc1wiIG9uQ2xpY2s9e29uQ2xvc2V9PlxuICAgICAgICAgIDxYIGNsYXNzTmFtZT1cInctNCBoLTRcIiAvPlxuICAgICAgICA8L0ljb25CdXR0b24+XG4gICAgICA8L2Rpdj5cbiAgICAgIDxkaXYgY2xhc3NOYW1lPVwib3ZlcmZsb3cteS1hdXRvIHAtMyBzcGFjZS15LTNcIj5cbiAgICAgICAgPGRsIGNsYXNzTmFtZT1cImdyaWQgZ3JpZC1jb2xzLVthdXRvXzFmcl0gZ2FwLXgtMyBnYXAteS0xLjUgdGV4dC1zbVwiPlxuICAgICAgICAgIDxkdCBjbGFzc05hbWU9XCJ0ZXh0LWdyYXktOTAwXCI+UmVzb3VyY2U8L2R0PlxuICAgICAgICAgIDxkZCBjbGFzc05hbWU9XCJ0ZXh0LWdyYXktMTAwMCBmb250LW1vbm9cIj57c3Bhbi5yZXNvdXJjZX08L2RkPlxuICAgICAgICAgIDxkdCBjbGFzc05hbWU9XCJ0ZXh0LWdyYXktOTAwXCI+RHVyYXRpb248L2R0PlxuICAgICAgICAgIDxkZCBjbGFzc05hbWU9XCJ0ZXh0LWdyYXktMTAwMCB0YWJ1bGFyLW51bXMgZm9udC1tb25vXCI+XG4gICAgICAgICAgICB7Zm9ybWF0RHVyYXRpb24oZHVyYXRpb25Ncyl9XG4gICAgICAgICAgPC9kZD5cbiAgICAgICAgICA8ZHQgY2xhc3NOYW1lPVwidGV4dC1ncmF5LTkwMFwiPk9mZnNldDwvZHQ+XG4gICAgICAgICAgPGRkIGNsYXNzTmFtZT1cInRleHQtZ3JheS0xMDAwIHRhYnVsYXItbnVtcyBmb250LW1vbm9cIj5cbiAgICAgICAgICAgICt7Zm9ybWF0RHVyYXRpb24ob2Zmc2V0TXMpfVxuICAgICAgICAgIDwvZGQ+XG4gICAgICAgICAgPGR0IGNsYXNzTmFtZT1cInRleHQtZ3JheS05MDBcIj5TdGF0dXM8L2R0PlxuICAgICAgICAgIDxkZCBjbGFzc05hbWU9XCJ0ZXh0LWdyYXktMTAwMCBmb250LW1vbm9cIj5cbiAgICAgICAgICAgIHtzcGFuLnN0YXR1cy5jb2RlID09PSAyID8gJ0Vycm9yJyA6ICdPSyd9XG4gICAgICAgICAgPC9kZD5cbiAgICAgICAgPC9kbD5cbiAgICAgIDwvZGl2PlxuICAgIDwvYXNpZGU+XG4gICk7XG59XG4iXX0=
@@ -1 +0,0 @@
1
- //# sourceMappingURL=constants.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../src/components/new-trace-viewer/util/constants.ts"],"names":[],"mappings":""}