@perses-dev/tracing-gantt-chart-plugin 0.12.1 → 0.13.0-beta.0

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 (228) hide show
  1. package/__mf/css/async/558.85c2cbf6.css +1 -0
  2. package/__mf/font/inter-cyrillic-300-normal.432f2b21.woff +0 -0
  3. package/__mf/font/inter-cyrillic-300-normal.9da91009.woff2 +0 -0
  4. package/__mf/font/inter-cyrillic-400-normal.372704ff.woff2 +0 -0
  5. package/__mf/font/inter-cyrillic-400-normal.a6b6ef6f.woff +0 -0
  6. package/__mf/font/inter-cyrillic-500-normal.7c15bba8.woff2 +0 -0
  7. package/__mf/font/inter-cyrillic-500-normal.b9f8c929.woff +0 -0
  8. package/__mf/font/inter-cyrillic-600-normal.2f42892a.woff2 +0 -0
  9. package/__mf/font/inter-cyrillic-600-normal.c3987adc.woff +0 -0
  10. package/__mf/font/inter-cyrillic-700-normal.93eba3c3.woff +0 -0
  11. package/__mf/font/inter-cyrillic-700-normal.e9e5b2dc.woff2 +0 -0
  12. package/__mf/font/inter-cyrillic-900-normal.f285bd7a.woff2 +0 -0
  13. package/__mf/font/inter-cyrillic-900-normal.ffbd8a3a.woff +0 -0
  14. package/__mf/font/inter-cyrillic-ext-300-normal.95bb9038.woff2 +0 -0
  15. package/__mf/font/inter-cyrillic-ext-300-normal.cfc143a9.woff +0 -0
  16. package/__mf/font/inter-cyrillic-ext-400-normal.2a31c04b.woff +0 -0
  17. package/__mf/font/inter-cyrillic-ext-400-normal.f572b170.woff2 +0 -0
  18. package/__mf/font/inter-cyrillic-ext-500-normal.5a6bb1da.woff +0 -0
  19. package/__mf/font/inter-cyrillic-ext-500-normal.fe0d9b14.woff2 +0 -0
  20. package/__mf/font/inter-cyrillic-ext-600-normal.ecbdecad.woff +0 -0
  21. package/__mf/font/inter-cyrillic-ext-600-normal.f7b3c15b.woff2 +0 -0
  22. package/__mf/font/inter-cyrillic-ext-700-normal.4b4022a6.woff +0 -0
  23. package/__mf/font/inter-cyrillic-ext-700-normal.74b516d2.woff2 +0 -0
  24. package/__mf/font/inter-cyrillic-ext-900-normal.9970ddb5.woff +0 -0
  25. package/__mf/font/inter-cyrillic-ext-900-normal.a0d59adc.woff2 +0 -0
  26. package/__mf/font/inter-greek-300-normal.0d7be683.woff2 +0 -0
  27. package/__mf/font/inter-greek-300-normal.8f0b988e.woff +0 -0
  28. package/__mf/font/inter-greek-400-normal.cc58c11b.woff +0 -0
  29. package/__mf/font/inter-greek-400-normal.d7020e3c.woff2 +0 -0
  30. package/__mf/font/inter-greek-500-normal.d9a33207.woff +0 -0
  31. package/__mf/font/inter-greek-500-normal.f41f43db.woff2 +0 -0
  32. package/__mf/font/inter-greek-600-normal.4ec0c1c1.woff +0 -0
  33. package/__mf/font/inter-greek-600-normal.cc532937.woff2 +0 -0
  34. package/__mf/font/inter-greek-700-normal.5ec6c758.woff +0 -0
  35. package/__mf/font/inter-greek-700-normal.97f0eeeb.woff2 +0 -0
  36. package/__mf/font/inter-greek-900-normal.46b66369.woff2 +0 -0
  37. package/__mf/font/inter-greek-900-normal.9ae3a3c5.woff +0 -0
  38. package/__mf/font/inter-greek-ext-300-normal.10247a66.woff2 +0 -0
  39. package/__mf/font/inter-greek-ext-300-normal.4668e5cb.woff +0 -0
  40. package/__mf/font/inter-greek-ext-400-normal.4ce1df5d.woff2 +0 -0
  41. package/__mf/font/inter-greek-ext-400-normal.88ede1ea.woff +0 -0
  42. package/__mf/font/inter-greek-ext-500-normal.7a4aa726.woff +0 -0
  43. package/__mf/font/inter-greek-ext-500-normal.cbd51e2d.woff2 +0 -0
  44. package/__mf/font/inter-greek-ext-600-normal.089a95ee.woff +0 -0
  45. package/__mf/font/inter-greek-ext-600-normal.1f33d317.woff2 +0 -0
  46. package/__mf/font/inter-greek-ext-700-normal.31f1075d.woff +0 -0
  47. package/__mf/font/inter-greek-ext-700-normal.827cd618.woff2 +0 -0
  48. package/__mf/font/inter-greek-ext-900-normal.531bcee7.woff +0 -0
  49. package/__mf/font/inter-greek-ext-900-normal.8a9b36b9.woff2 +0 -0
  50. package/__mf/font/inter-latin-300-normal.15fb600d.woff2 +0 -0
  51. package/__mf/font/inter-latin-300-normal.6f95f590.woff +0 -0
  52. package/__mf/font/inter-latin-400-normal.2c7a775c.woff +0 -0
  53. package/__mf/font/inter-latin-400-normal.ef6d3f52.woff2 +0 -0
  54. package/__mf/font/inter-latin-500-normal.b7b43ace.woff2 +0 -0
  55. package/__mf/font/inter-latin-500-normal.cb4c8ceb.woff +0 -0
  56. package/__mf/font/inter-latin-600-normal.8fb1a964.woff2 +0 -0
  57. package/__mf/font/inter-latin-600-normal.ce0f5f43.woff +0 -0
  58. package/__mf/font/inter-latin-700-normal.953b7aa5.woff2 +0 -0
  59. package/__mf/font/inter-latin-700-normal.9c21d4dc.woff +0 -0
  60. package/__mf/font/inter-latin-900-normal.2a8028ec.woff2 +0 -0
  61. package/__mf/font/inter-latin-900-normal.fa252135.woff +0 -0
  62. package/__mf/font/inter-latin-ext-300-normal.167cc8c9.woff2 +0 -0
  63. package/__mf/font/inter-latin-ext-300-normal.f695be66.woff +0 -0
  64. package/__mf/font/inter-latin-ext-400-normal.32a25442.woff2 +0 -0
  65. package/__mf/font/inter-latin-ext-400-normal.4edcaace.woff +0 -0
  66. package/__mf/font/inter-latin-ext-500-normal.a19a84a6.woff +0 -0
  67. package/__mf/font/inter-latin-ext-500-normal.d9b491de.woff2 +0 -0
  68. package/__mf/font/inter-latin-ext-600-normal.38b075d8.woff2 +0 -0
  69. package/__mf/font/inter-latin-ext-600-normal.49faa47a.woff +0 -0
  70. package/__mf/font/inter-latin-ext-700-normal.93534b50.woff +0 -0
  71. package/__mf/font/inter-latin-ext-700-normal.b63daa1a.woff2 +0 -0
  72. package/__mf/font/inter-latin-ext-900-normal.0efdb307.woff +0 -0
  73. package/__mf/font/inter-latin-ext-900-normal.9c0fc2c7.woff2 +0 -0
  74. package/__mf/font/inter-vietnamese-300-normal.aad496d8.woff +0 -0
  75. package/__mf/font/inter-vietnamese-300-normal.ad9ef503.woff2 +0 -0
  76. package/__mf/font/inter-vietnamese-400-normal.a9dd2faf.woff +0 -0
  77. package/__mf/font/inter-vietnamese-400-normal.de4fc44f.woff2 +0 -0
  78. package/__mf/font/inter-vietnamese-500-normal.7c0a695f.woff2 +0 -0
  79. package/__mf/font/inter-vietnamese-500-normal.a3a73b95.woff +0 -0
  80. package/__mf/font/inter-vietnamese-600-normal.9d518599.woff2 +0 -0
  81. package/__mf/font/inter-vietnamese-600-normal.c5ce3fcb.woff +0 -0
  82. package/__mf/font/inter-vietnamese-700-normal.bc68b199.woff +0 -0
  83. package/__mf/font/inter-vietnamese-700-normal.faf12809.woff2 +0 -0
  84. package/__mf/font/inter-vietnamese-900-normal.2b782045.woff +0 -0
  85. package/__mf/font/inter-vietnamese-900-normal.e639b65a.woff2 +0 -0
  86. package/__mf/js/TracingGanttChart.a69ad65c.js +7 -0
  87. package/__mf/js/async/121.5475779f.js +2 -0
  88. package/__mf/js/async/177.50257b88.js +1 -0
  89. package/__mf/js/async/192.a0a2e63b.js +1 -0
  90. package/__mf/js/async/2.d2c2e5a6.js +1 -0
  91. package/__mf/js/async/207.dcd0ae82.js +110 -0
  92. package/__mf/js/async/{666.4cf9c453.js.LICENSE.txt → 207.dcd0ae82.js.LICENSE.txt} +1 -1
  93. package/__mf/js/async/235.b42801b1.js +1 -0
  94. package/__mf/js/async/274.5c518455.js +2 -0
  95. package/__mf/js/async/356.fc2da489.js +1 -0
  96. package/__mf/js/async/366.0baba713.js +24 -0
  97. package/__mf/js/async/{634.b68acb18.js.LICENSE.txt → 366.0baba713.js.LICENSE.txt} +1 -1
  98. package/__mf/js/async/392.6c066266.js +2 -0
  99. package/__mf/js/async/43.e395f769.js +2 -0
  100. package/__mf/js/async/470.4e137e17.js +2 -0
  101. package/__mf/js/async/472.8aa138b3.js +1 -0
  102. package/__mf/js/async/558.c4505dfb.js +7 -0
  103. package/__mf/js/async/{12.c9423551.js.LICENSE.txt → 558.c4505dfb.js.LICENSE.txt} +19 -1
  104. package/__mf/js/async/581.530a1cbc.js +1 -0
  105. package/__mf/js/async/587.dbc05176.js +1 -0
  106. package/__mf/js/async/588.f5afdb25.js +1 -0
  107. package/__mf/js/async/616.268fac9b.js +1 -0
  108. package/__mf/js/async/71.79ef5248.js +1 -0
  109. package/__mf/js/async/729.b8d22843.js +39 -0
  110. package/__mf/js/async/873.76af63d7.js +1 -0
  111. package/__mf/js/async/895.7c3edbda.js +1 -0
  112. package/__mf/js/async/941.70c6480d.js +2 -0
  113. package/__mf/js/async/968.68803274.js +1 -0
  114. package/__mf/js/async/978.ca0b1b55.js +1 -0
  115. package/__mf/js/async/__federation_expose_TracingGanttChart.2f3100da.js +1 -0
  116. package/__mf/js/async/lib-router.69a7062a.js +2 -0
  117. package/__mf/js/main.62d36e4e.js +7 -0
  118. package/lib/TracingGanttChart/DetailPane/Attributes.d.ts +1 -0
  119. package/lib/TracingGanttChart/DetailPane/Attributes.d.ts.map +1 -1
  120. package/lib/TracingGanttChart/DetailPane/Attributes.js +45 -8
  121. package/lib/TracingGanttChart/DetailPane/Attributes.js.map +1 -1
  122. package/lib/TracingGanttChart/GanttTable/GanttTable.d.ts +2 -0
  123. package/lib/TracingGanttChart/GanttTable/GanttTable.d.ts.map +1 -1
  124. package/lib/TracingGanttChart/GanttTable/GanttTable.js +64 -25
  125. package/lib/TracingGanttChart/GanttTable/GanttTable.js.map +1 -1
  126. package/lib/TracingGanttChart/GanttTable/GanttTableProvider.d.ts +2 -2
  127. package/lib/TracingGanttChart/GanttTable/GanttTableProvider.d.ts.map +1 -1
  128. package/lib/TracingGanttChart/GanttTable/GanttTableProvider.js +1 -1
  129. package/lib/TracingGanttChart/GanttTable/GanttTableProvider.js.map +1 -1
  130. package/lib/TracingGanttChart/GanttTable/GanttTableRow.d.ts +5 -0
  131. package/lib/TracingGanttChart/GanttTable/GanttTableRow.d.ts.map +1 -1
  132. package/lib/TracingGanttChart/GanttTable/GanttTableRow.js +14 -2
  133. package/lib/TracingGanttChart/GanttTable/GanttTableRow.js.map +1 -1
  134. package/lib/TracingGanttChart/GanttTable/ResizableDivider.d.ts.map +1 -1
  135. package/lib/TracingGanttChart/GanttTable/ResizableDivider.js +6 -2
  136. package/lib/TracingGanttChart/GanttTable/ResizableDivider.js.map +1 -1
  137. package/lib/TracingGanttChart/GanttTable/SpanIndents.d.ts.map +1 -1
  138. package/lib/TracingGanttChart/GanttTable/SpanIndents.js +10 -10
  139. package/lib/TracingGanttChart/GanttTable/SpanIndents.js.map +1 -1
  140. package/lib/TracingGanttChart/MiniGanttChart/draw.d.ts.map +1 -1
  141. package/lib/TracingGanttChart/MiniGanttChart/draw.js +2 -6
  142. package/lib/TracingGanttChart/MiniGanttChart/draw.js.map +1 -1
  143. package/lib/TracingGanttChart/Search.d.ts +15 -0
  144. package/lib/TracingGanttChart/Search.d.ts.map +1 -0
  145. package/lib/TracingGanttChart/Search.js +133 -0
  146. package/lib/TracingGanttChart/Search.js.map +1 -0
  147. package/lib/TracingGanttChart/TraceHeaderBar.d.ts +9 -0
  148. package/lib/TracingGanttChart/TraceHeaderBar.d.ts.map +1 -0
  149. package/lib/TracingGanttChart/TraceHeaderBar.js +126 -0
  150. package/lib/TracingGanttChart/TraceHeaderBar.js.map +1 -0
  151. package/lib/TracingGanttChart/TracingGanttChart.d.ts.map +1 -1
  152. package/lib/TracingGanttChart/TracingGanttChart.js +14 -8
  153. package/lib/TracingGanttChart/TracingGanttChart.js.map +1 -1
  154. package/lib/TracingGanttChart/trace.d.ts +5 -0
  155. package/lib/TracingGanttChart/trace.d.ts.map +1 -1
  156. package/lib/TracingGanttChart/trace.js +10 -0
  157. package/lib/TracingGanttChart/trace.js.map +1 -1
  158. package/lib/cjs/TracingGanttChart/DetailPane/Attributes.js +47 -7
  159. package/lib/cjs/TracingGanttChart/GanttTable/GanttTable.js +63 -24
  160. package/lib/cjs/TracingGanttChart/GanttTable/GanttTableProvider.js +1 -1
  161. package/lib/cjs/TracingGanttChart/GanttTable/GanttTableRow.js +14 -2
  162. package/lib/cjs/TracingGanttChart/GanttTable/ResizableDivider.js +6 -2
  163. package/lib/cjs/TracingGanttChart/GanttTable/SpanIndents.js +10 -10
  164. package/lib/cjs/TracingGanttChart/MiniGanttChart/draw.js +2 -6
  165. package/lib/cjs/TracingGanttChart/Search.js +154 -0
  166. package/lib/cjs/TracingGanttChart/TraceHeaderBar.js +139 -0
  167. package/lib/cjs/TracingGanttChart/TracingGanttChart.js +13 -7
  168. package/lib/cjs/TracingGanttChart/trace.js +18 -3
  169. package/mf-manifest.json +61 -50
  170. package/mf-stats.json +72 -50
  171. package/package.json +5 -4
  172. package/__mf/css/async/442.d3010b86.css +0 -1
  173. package/__mf/css/async/61.d3010b86.css +0 -1
  174. package/__mf/css/async/823.d3010b86.css +0 -1
  175. package/__mf/font/lato-all-300-normal.322bdf14.woff +0 -0
  176. package/__mf/font/lato-all-400-normal.63513b00.woff +0 -0
  177. package/__mf/font/lato-all-700-normal.bb27db94.woff +0 -0
  178. package/__mf/font/lato-all-900-normal.a27049a3.woff +0 -0
  179. package/__mf/font/lato-latin-300-normal.c5195215.woff2 +0 -0
  180. package/__mf/font/lato-latin-400-normal.b7ffde23.woff2 +0 -0
  181. package/__mf/font/lato-latin-700-normal.d5eb20bc.woff2 +0 -0
  182. package/__mf/font/lato-latin-900-normal.d884a71c.woff2 +0 -0
  183. package/__mf/font/lato-latin-ext-300-normal.abcc64a9.woff2 +0 -0
  184. package/__mf/font/lato-latin-ext-400-normal.6ebed106.woff2 +0 -0
  185. package/__mf/font/lato-latin-ext-700-normal.8697d1d5.woff2 +0 -0
  186. package/__mf/font/lato-latin-ext-900-normal.20a2b415.woff2 +0 -0
  187. package/__mf/js/TracingGanttChart.f5573ac3.js +0 -6
  188. package/__mf/js/async/12.c9423551.js +0 -7
  189. package/__mf/js/async/121.cb300887.js +0 -2
  190. package/__mf/js/async/157.77f5f5a1.js +0 -39
  191. package/__mf/js/async/177.cf9df204.js +0 -1
  192. package/__mf/js/async/192.f723a636.js +0 -1
  193. package/__mf/js/async/2.e3ce4ee4.js +0 -1
  194. package/__mf/js/async/235.806ca841.js +0 -1
  195. package/__mf/js/async/274.457dda65.js +0 -2
  196. package/__mf/js/async/356.7ea3eee9.js +0 -1
  197. package/__mf/js/async/392.c563796d.js +0 -2
  198. package/__mf/js/async/43.55c495e3.js +0 -2
  199. package/__mf/js/async/439.63c7b180.js +0 -1
  200. package/__mf/js/async/470.f5dfd429.js +0 -2
  201. package/__mf/js/async/587.3a4d8eed.js +0 -1
  202. package/__mf/js/async/588.a1fce2da.js +0 -1
  203. package/__mf/js/async/616.25399954.js +0 -1
  204. package/__mf/js/async/634.b68acb18.js +0 -24
  205. package/__mf/js/async/666.4cf9c453.js +0 -110
  206. package/__mf/js/async/71.ec1919d7.js +0 -1
  207. package/__mf/js/async/751.b7c40fc8.js +0 -1
  208. package/__mf/js/async/873.0f298220.js +0 -1
  209. package/__mf/js/async/895.eb528fc2.js +0 -1
  210. package/__mf/js/async/941.065a3eec.js +0 -2
  211. package/__mf/js/async/968.5f7ccf5e.js +0 -1
  212. package/__mf/js/async/978.151ab551.js +0 -1
  213. package/__mf/js/async/__federation_expose_TracingGanttChart.3ea317ee.js +0 -1
  214. package/__mf/js/async/lib-router.aed93ee9.js +0 -2
  215. package/__mf/js/main.237de7d0.js +0 -6
  216. package/lib/TracingGanttChart/TraceDetails.d.ts +0 -7
  217. package/lib/TracingGanttChart/TraceDetails.d.ts.map +0 -1
  218. package/lib/TracingGanttChart/TraceDetails.js +0 -90
  219. package/lib/TracingGanttChart/TraceDetails.js.map +0 -1
  220. package/lib/cjs/TracingGanttChart/TraceDetails.js +0 -98
  221. /package/__mf/js/async/{121.cb300887.js.LICENSE.txt → 121.5475779f.js.LICENSE.txt} +0 -0
  222. /package/__mf/js/async/{274.457dda65.js.LICENSE.txt → 274.5c518455.js.LICENSE.txt} +0 -0
  223. /package/__mf/js/async/{392.c563796d.js.LICENSE.txt → 392.6c066266.js.LICENSE.txt} +0 -0
  224. /package/__mf/js/async/{43.55c495e3.js.LICENSE.txt → 43.e395f769.js.LICENSE.txt} +0 -0
  225. /package/__mf/js/async/{470.f5dfd429.js.LICENSE.txt → 470.4e137e17.js.LICENSE.txt} +0 -0
  226. /package/__mf/js/async/{157.77f5f5a1.js.LICENSE.txt → 729.b8d22843.js.LICENSE.txt} +0 -0
  227. /package/__mf/js/async/{941.065a3eec.js.LICENSE.txt → 941.70c6480d.js.LICENSE.txt} +0 -0
  228. /package/__mf/js/async/{lib-router.aed93ee9.js.LICENSE.txt → lib-router.69a7062a.js.LICENSE.txt} +0 -0
@@ -0,0 +1,126 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ // Copyright The Perses Authors
3
+ // Licensed under the Apache License, Version 2.0 (the "License");
4
+ // you may not use this file except in compliance with the License.
5
+ // You may obtain a copy of the License at
6
+ //
7
+ // http://www.apache.org/licenses/LICENSE-2.0
8
+ //
9
+ // Unless required by applicable law or agreed to in writing, software
10
+ // distributed under the License is distributed on an "AS IS" BASIS,
11
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
+ // See the License for the specific language governing permissions and
13
+ // limitations under the License.
14
+ import { IconButton, Stack, Typography } from '@mui/material';
15
+ import MagnifyIcon from 'mdi-material-ui/Magnify';
16
+ import { useMemo, useState } from 'react';
17
+ import { useTimeZone } from '@perses-dev/components';
18
+ import { formatDuration } from './utils';
19
+ import { SearchBar } from './Search';
20
+ const DATE_FORMAT_OPTIONS = {
21
+ year: 'numeric',
22
+ month: 'long',
23
+ day: 'numeric',
24
+ hour: 'numeric',
25
+ minute: 'numeric',
26
+ second: 'numeric',
27
+ fractionalSecondDigits: 3,
28
+ timeZoneName: 'short'
29
+ };
30
+ export function TraceHeaderBar(props) {
31
+ const { trace, search } = props;
32
+ const { dateFormatOptionsWithUserTimeZone } = useTimeZone();
33
+ const dateFormatter = useMemo(()=>{
34
+ const dateFormatOptions = dateFormatOptionsWithUserTimeZone(DATE_FORMAT_OPTIONS);
35
+ return new Intl.DateTimeFormat(undefined, dateFormatOptions);
36
+ }, [
37
+ dateFormatOptionsWithUserTimeZone
38
+ ]);
39
+ const [showSearch, setShowSearch] = useState(false);
40
+ const rootSpan = trace.rootSpans[0];
41
+ if (!rootSpan) {
42
+ return /*#__PURE__*/ _jsx(Typography, {
43
+ children: "Trace contains no spans."
44
+ });
45
+ }
46
+ return /*#__PURE__*/ _jsxs(Stack, {
47
+ direction: "column",
48
+ sx: {
49
+ gap: 1
50
+ },
51
+ children: [
52
+ /*#__PURE__*/ _jsxs(Stack, {
53
+ direction: "row",
54
+ sx: {
55
+ justifyContent: 'space-between'
56
+ },
57
+ children: [
58
+ /*#__PURE__*/ _jsxs(Stack, {
59
+ direction: "row",
60
+ sx: {
61
+ gap: 1,
62
+ alignItems: 'center'
63
+ },
64
+ children: [
65
+ /*#__PURE__*/ _jsxs(Typography, {
66
+ variant: "h3",
67
+ children: [
68
+ rootSpan.resource.serviceName,
69
+ ": ",
70
+ rootSpan.name,
71
+ " (",
72
+ formatDuration(trace.endTimeUnixMs - trace.startTimeUnixMs),
73
+ ")"
74
+ ]
75
+ }),
76
+ /*#__PURE__*/ _jsx(IconButton, {
77
+ size: "small",
78
+ onClick: ()=>setShowSearch((prev)=>!prev),
79
+ "aria-label": "Toggle search",
80
+ children: /*#__PURE__*/ _jsx(MagnifyIcon, {
81
+ fontSize: "small"
82
+ })
83
+ })
84
+ ]
85
+ }),
86
+ /*#__PURE__*/ _jsxs(Typography, {
87
+ variant: "h4",
88
+ children: [
89
+ /*#__PURE__*/ _jsxs(Typography, {
90
+ component: "span",
91
+ sx: {
92
+ px: 1
93
+ },
94
+ children: [
95
+ /*#__PURE__*/ _jsx("strong", {
96
+ children: "Start:"
97
+ }),
98
+ " ",
99
+ dateFormatter.format(trace.startTimeUnixMs)
100
+ ]
101
+ }),
102
+ /*#__PURE__*/ _jsxs(Typography, {
103
+ component: "span",
104
+ sx: {
105
+ px: 1
106
+ },
107
+ children: [
108
+ /*#__PURE__*/ _jsx("strong", {
109
+ children: "Trace ID:"
110
+ }),
111
+ " ",
112
+ rootSpan.traceId
113
+ ]
114
+ })
115
+ ]
116
+ })
117
+ ]
118
+ }),
119
+ showSearch && /*#__PURE__*/ _jsx(SearchBar, {
120
+ search: search
121
+ })
122
+ ]
123
+ });
124
+ }
125
+
126
+ //# sourceMappingURL=TraceHeaderBar.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../src/TracingGanttChart/TraceHeaderBar.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { IconButton, Stack, Typography } from '@mui/material';\nimport MagnifyIcon from 'mdi-material-ui/Magnify';\nimport { ReactElement, useMemo, useState } from 'react';\nimport { useTimeZone } from '@perses-dev/components';\nimport { formatDuration } from './utils';\nimport { Trace } from './trace';\nimport { SearchBar, SpanSearch } from './Search';\n\nconst DATE_FORMAT_OPTIONS: Intl.DateTimeFormatOptions = {\n year: 'numeric',\n month: 'long',\n day: 'numeric',\n hour: 'numeric',\n minute: 'numeric',\n second: 'numeric',\n fractionalSecondDigits: 3,\n timeZoneName: 'short',\n};\n\nexport interface TraceHeaderBarProps {\n trace: Trace;\n search: SpanSearch;\n}\n\nexport function TraceHeaderBar(props: TraceHeaderBarProps): ReactElement {\n const { trace, search } = props;\n\n const { dateFormatOptionsWithUserTimeZone } = useTimeZone();\n const dateFormatter = useMemo(() => {\n const dateFormatOptions = dateFormatOptionsWithUserTimeZone(DATE_FORMAT_OPTIONS);\n return new Intl.DateTimeFormat(undefined, dateFormatOptions);\n }, [dateFormatOptionsWithUserTimeZone]);\n const [showSearch, setShowSearch] = useState(false);\n\n const rootSpan = trace.rootSpans[0];\n if (!rootSpan) {\n return <Typography>Trace contains no spans.</Typography>;\n }\n\n return (\n <Stack direction=\"column\" sx={{ gap: 1 }}>\n <Stack direction=\"row\" sx={{ justifyContent: 'space-between' }}>\n <Stack direction=\"row\" sx={{ gap: 1, alignItems: 'center' }}>\n <Typography variant=\"h3\">\n {rootSpan.resource.serviceName}: {rootSpan.name} (\n {formatDuration(trace.endTimeUnixMs - trace.startTimeUnixMs)})\n </Typography>\n <IconButton size=\"small\" onClick={() => setShowSearch((prev) => !prev)} aria-label=\"Toggle search\">\n <MagnifyIcon fontSize=\"small\" />\n </IconButton>\n </Stack>\n <Typography variant=\"h4\">\n <Typography component=\"span\" sx={{ px: 1 }}>\n <strong>Start:</strong> {dateFormatter.format(trace.startTimeUnixMs)}\n </Typography>\n <Typography component=\"span\" sx={{ px: 1 }}>\n <strong>Trace ID:</strong> {rootSpan.traceId}\n </Typography>\n </Typography>\n </Stack>\n {showSearch && <SearchBar search={search} />}\n </Stack>\n );\n}\n"],"names":["IconButton","Stack","Typography","MagnifyIcon","useMemo","useState","useTimeZone","formatDuration","SearchBar","DATE_FORMAT_OPTIONS","year","month","day","hour","minute","second","fractionalSecondDigits","timeZoneName","TraceHeaderBar","props","trace","search","dateFormatOptionsWithUserTimeZone","dateFormatter","dateFormatOptions","Intl","DateTimeFormat","undefined","showSearch","setShowSearch","rootSpan","rootSpans","direction","sx","gap","justifyContent","alignItems","variant","resource","serviceName","name","endTimeUnixMs","startTimeUnixMs","size","onClick","prev","aria-label","fontSize","component","px","strong","format","traceId"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAASA,UAAU,EAAEC,KAAK,EAAEC,UAAU,QAAQ,gBAAgB;AAC9D,OAAOC,iBAAiB,0BAA0B;AAClD,SAAuBC,OAAO,EAAEC,QAAQ,QAAQ,QAAQ;AACxD,SAASC,WAAW,QAAQ,yBAAyB;AACrD,SAASC,cAAc,QAAQ,UAAU;AAEzC,SAASC,SAAS,QAAoB,WAAW;AAEjD,MAAMC,sBAAkD;IACtDC,MAAM;IACNC,OAAO;IACPC,KAAK;IACLC,MAAM;IACNC,QAAQ;IACRC,QAAQ;IACRC,wBAAwB;IACxBC,cAAc;AAChB;AAOA,OAAO,SAASC,eAAeC,KAA0B;IACvD,MAAM,EAAEC,KAAK,EAAEC,MAAM,EAAE,GAAGF;IAE1B,MAAM,EAAEG,iCAAiC,EAAE,GAAGhB;IAC9C,MAAMiB,gBAAgBnB,QAAQ;QAC5B,MAAMoB,oBAAoBF,kCAAkCb;QAC5D,OAAO,IAAIgB,KAAKC,cAAc,CAACC,WAAWH;IAC5C,GAAG;QAACF;KAAkC;IACtC,MAAM,CAACM,YAAYC,cAAc,GAAGxB,SAAS;IAE7C,MAAMyB,WAAWV,MAAMW,SAAS,CAAC,EAAE;IACnC,IAAI,CAACD,UAAU;QACb,qBAAO,KAAC5B;sBAAW;;IACrB;IAEA,qBACE,MAACD;QAAM+B,WAAU;QAASC,IAAI;YAAEC,KAAK;QAAE;;0BACrC,MAACjC;gBAAM+B,WAAU;gBAAMC,IAAI;oBAAEE,gBAAgB;gBAAgB;;kCAC3D,MAAClC;wBAAM+B,WAAU;wBAAMC,IAAI;4BAAEC,KAAK;4BAAGE,YAAY;wBAAS;;0CACxD,MAAClC;gCAAWmC,SAAQ;;oCACjBP,SAASQ,QAAQ,CAACC,WAAW;oCAAC;oCAAGT,SAASU,IAAI;oCAAC;oCAC/CjC,eAAea,MAAMqB,aAAa,GAAGrB,MAAMsB,eAAe;oCAAE;;;0CAE/D,KAAC1C;gCAAW2C,MAAK;gCAAQC,SAAS,IAAMf,cAAc,CAACgB,OAAS,CAACA;gCAAOC,cAAW;0CACjF,cAAA,KAAC3C;oCAAY4C,UAAS;;;;;kCAG1B,MAAC7C;wBAAWmC,SAAQ;;0CAClB,MAACnC;gCAAW8C,WAAU;gCAAOf,IAAI;oCAAEgB,IAAI;gCAAE;;kDACvC,KAACC;kDAAO;;oCAAe;oCAAE3B,cAAc4B,MAAM,CAAC/B,MAAMsB,eAAe;;;0CAErE,MAACxC;gCAAW8C,WAAU;gCAAOf,IAAI;oCAAEgB,IAAI;gCAAE;;kDACvC,KAACC;kDAAO;;oCAAkB;oCAAEpB,SAASsB,OAAO;;;;;;;YAIjDxB,4BAAc,KAACpB;gBAAUa,QAAQA;;;;AAGxC"}
@@ -1 +1 @@
1
- {"version":3,"file":"TracingGanttChart.d.ts","sourceRoot":"","sources":["../../../src/TracingGanttChart/TracingGanttChart.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAA6B,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAU7E,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,wBAAwB,CAAC;IAClC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAwD7E"}
1
+ {"version":3,"file":"TracingGanttChart.d.ts","sourceRoot":"","sources":["../../../src/TracingGanttChart/TracingGanttChart.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAA6B,MAAM,OAAO,CAAC;AAEhE,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAW7E,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,wBAAwB,CAAC;IAClC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;CAC/B;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,GAAG,YAAY,CAiE7E"}
@@ -12,14 +12,15 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { useMemo, useRef, useState } from 'react';
15
- import { Box, Stack, useTheme } from '@mui/material';
15
+ import { Box, Stack } from '@mui/material';
16
16
  import { MiniGanttChart } from './MiniGanttChart/MiniGanttChart';
17
17
  import { DetailPane } from './DetailPane/DetailPane';
18
18
  import { GanttTable } from './GanttTable/GanttTable';
19
19
  import { GanttTableProvider } from './GanttTable/GanttTableProvider';
20
20
  import { ResizableDivider } from './GanttTable/ResizableDivider';
21
21
  import { getTraceModel } from './trace';
22
- import { TraceDetails } from './TraceDetails';
22
+ import { TraceHeaderBar } from './TraceHeaderBar';
23
+ import { useSpanSearch } from './Search';
23
24
  /**
24
25
  * The core GanttChart panel for Perses.
25
26
  *
@@ -27,7 +28,6 @@ import { TraceDetails } from './TraceDetails';
27
28
  * https://github.com/jaegertracing/jaeger-ui
28
29
  */ export function TracingGanttChart(props) {
29
30
  const { options, customLinks, trace: otlpTrace } = props;
30
- const theme = useTheme();
31
31
  const trace = useMemo(()=>{
32
32
  try {
33
33
  return getTraceModel(otlpTrace);
@@ -42,11 +42,13 @@ import { TraceDetails } from './TraceDetails';
42
42
  endTimeUnixMs: trace.endTimeUnixMs
43
43
  });
44
44
  const [selectedSpan, setSelectedSpan] = useState(()=>options.selectedSpanId ? trace.spanById.get(options.selectedSpanId) : undefined);
45
+ const search = useSpanSearch(trace);
45
46
  const ganttChart = useRef(null);
46
47
  // tableWidth only comes to effect if the detail pane is visible.
47
48
  // setTableWidth() is only called by <ResizableDivider />
48
49
  const [tableWidth, setTableWidth] = useState(0.82);
49
50
  const gap = 2;
51
+ const spacing = ganttChart.current ? parseFloat(getComputedStyle(ganttChart.current).columnGap) || 0 : 0;
50
52
  return /*#__PURE__*/ _jsxs(Stack, {
51
53
  ref: ganttChart,
52
54
  direction: "row",
@@ -62,8 +64,9 @@ import { TraceDetails } from './TraceDetails';
62
64
  gap
63
65
  },
64
66
  children: [
65
- /*#__PURE__*/ _jsx(TraceDetails, {
66
- trace: trace
67
+ /*#__PURE__*/ _jsx(TraceHeaderBar, {
68
+ trace: trace,
69
+ search: search
67
70
  }),
68
71
  /*#__PURE__*/ _jsx(MiniGanttChart, {
69
72
  options: options,
@@ -78,7 +81,9 @@ import { TraceDetails } from './TraceDetails';
78
81
  trace: trace,
79
82
  viewport: viewport,
80
83
  selectedSpan: selectedSpan,
81
- onSpanClick: setSelectedSpan
84
+ onSpanClick: setSelectedSpan,
85
+ matchingSpanIds: search.matchingSpanIds,
86
+ focusedSpanId: search.matchingSpanIds[search.focusedMatchIndex]
82
87
  })
83
88
  })
84
89
  ]
@@ -87,12 +92,13 @@ import { TraceDetails } from './TraceDetails';
87
92
  children: [
88
93
  /*#__PURE__*/ _jsx(ResizableDivider, {
89
94
  parentRef: ganttChart,
90
- spacing: parseInt(theme.spacing(gap)),
95
+ spacing: spacing,
91
96
  onMove: setTableWidth
92
97
  }),
93
98
  /*#__PURE__*/ _jsx(Box, {
94
99
  style: {
95
- width: `${(1 - tableWidth) * 100}%`
100
+ width: `${(1 - tableWidth) * 100}%`,
101
+ minWidth: `${(1 - tableWidth) * 100}%`
96
102
  },
97
103
  sx: {
98
104
  overflow: 'auto'
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/TracingGanttChart/TracingGanttChart.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo, useRef, useState } from 'react';\nimport { Box, Stack, useTheme } from '@mui/material';\nimport { otlptracev1 } from '@perses-dev/core';\nimport { CustomLinks, TracingGanttChartOptions } from '../gantt-chart-model';\nimport { MiniGanttChart } from './MiniGanttChart/MiniGanttChart';\nimport { DetailPane } from './DetailPane/DetailPane';\nimport { Viewport } from './utils';\nimport { GanttTable } from './GanttTable/GanttTable';\nimport { GanttTableProvider } from './GanttTable/GanttTableProvider';\nimport { ResizableDivider } from './GanttTable/ResizableDivider';\nimport { getTraceModel, Span } from './trace';\nimport { TraceDetails } from './TraceDetails';\n\nexport interface TracingGanttChartProps {\n options: TracingGanttChartOptions;\n customLinks?: CustomLinks;\n trace: otlptracev1.TracesData;\n}\n\n/**\n * The core GanttChart panel for Perses.\n *\n * The UI/UX of this panel is based on Jaeger UI, licensed under Apache License, Version 2.0.\n * https://github.com/jaegertracing/jaeger-ui\n */\nexport function TracingGanttChart(props: TracingGanttChartProps): ReactElement {\n const { options, customLinks, trace: otlpTrace } = props;\n\n const theme = useTheme();\n const trace = useMemo(() => {\n try {\n return getTraceModel(otlpTrace);\n } catch (e) {\n throw new Error(`Error: unable to parse trace: ${e}`);\n }\n }, [otlpTrace]);\n const [viewport, setViewport] = useState<Viewport>({\n startTimeUnixMs: trace.startTimeUnixMs,\n endTimeUnixMs: trace.endTimeUnixMs,\n });\n const [selectedSpan, setSelectedSpan] = useState<Span | undefined>(() =>\n options.selectedSpanId ? trace.spanById.get(options.selectedSpanId) : undefined\n );\n\n const ganttChart = useRef<HTMLDivElement>(null);\n // tableWidth only comes to effect if the detail pane is visible.\n // setTableWidth() is only called by <ResizableDivider />\n const [tableWidth, setTableWidth] = useState<number>(0.82);\n const gap = 2;\n\n return (\n <Stack ref={ganttChart} direction=\"row\" sx={{ height: '100%', minHeight: '240px', gap }}>\n <Stack sx={{ flexGrow: 1, gap }}>\n <TraceDetails trace={trace} />\n <MiniGanttChart options={options} trace={trace} viewport={viewport} setViewport={setViewport} />\n <GanttTableProvider>\n <GanttTable\n options={options}\n customLinks={customLinks}\n trace={trace}\n viewport={viewport}\n selectedSpan={selectedSpan}\n onSpanClick={setSelectedSpan}\n />\n </GanttTableProvider>\n </Stack>\n {selectedSpan && (\n <>\n <ResizableDivider parentRef={ganttChart} spacing={parseInt(theme.spacing(gap))} onMove={setTableWidth} />\n <Box style={{ width: `${(1 - tableWidth) * 100}%` }} sx={{ overflow: 'auto' }}>\n <DetailPane\n customLinks={customLinks}\n trace={trace}\n span={selectedSpan}\n onCloseBtnClick={() => setSelectedSpan(undefined)}\n />\n </Box>\n </>\n )}\n </Stack>\n );\n}\n"],"names":["useMemo","useRef","useState","Box","Stack","useTheme","MiniGanttChart","DetailPane","GanttTable","GanttTableProvider","ResizableDivider","getTraceModel","TraceDetails","TracingGanttChart","props","options","customLinks","trace","otlpTrace","theme","e","Error","viewport","setViewport","startTimeUnixMs","endTimeUnixMs","selectedSpan","setSelectedSpan","selectedSpanId","spanById","get","undefined","ganttChart","tableWidth","setTableWidth","gap","ref","direction","sx","height","minHeight","flexGrow","onSpanClick","parentRef","spacing","parseInt","onMove","style","width","overflow","span","onCloseBtnClick"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAAuBA,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAChE,SAASC,GAAG,EAAEC,KAAK,EAAEC,QAAQ,QAAQ,gBAAgB;AAGrD,SAASC,cAAc,QAAQ,kCAAkC;AACjE,SAASC,UAAU,QAAQ,0BAA0B;AAErD,SAASC,UAAU,QAAQ,0BAA0B;AACrD,SAASC,kBAAkB,QAAQ,kCAAkC;AACrE,SAASC,gBAAgB,QAAQ,gCAAgC;AACjE,SAASC,aAAa,QAAc,UAAU;AAC9C,SAASC,YAAY,QAAQ,iBAAiB;AAQ9C;;;;;CAKC,GACD,OAAO,SAASC,kBAAkBC,KAA6B;IAC7D,MAAM,EAAEC,OAAO,EAAEC,WAAW,EAAEC,OAAOC,SAAS,EAAE,GAAGJ;IAEnD,MAAMK,QAAQd;IACd,MAAMY,QAAQjB,QAAQ;QACpB,IAAI;YACF,OAAOW,cAAcO;QACvB,EAAE,OAAOE,GAAG;YACV,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAED,GAAG;QACtD;IACF,GAAG;QAACF;KAAU;IACd,MAAM,CAACI,UAAUC,YAAY,GAAGrB,SAAmB;QACjDsB,iBAAiBP,MAAMO,eAAe;QACtCC,eAAeR,MAAMQ,aAAa;IACpC;IACA,MAAM,CAACC,cAAcC,gBAAgB,GAAGzB,SAA2B,IACjEa,QAAQa,cAAc,GAAGX,MAAMY,QAAQ,CAACC,GAAG,CAACf,QAAQa,cAAc,IAAIG;IAGxE,MAAMC,aAAa/B,OAAuB;IAC1C,iEAAiE;IACjE,yDAAyD;IACzD,MAAM,CAACgC,YAAYC,cAAc,GAAGhC,SAAiB;IACrD,MAAMiC,MAAM;IAEZ,qBACE,MAAC/B;QAAMgC,KAAKJ;QAAYK,WAAU;QAAMC,IAAI;YAAEC,QAAQ;YAAQC,WAAW;YAASL;QAAI;;0BACpF,MAAC/B;gBAAMkC,IAAI;oBAAEG,UAAU;oBAAGN;gBAAI;;kCAC5B,KAACvB;wBAAaK,OAAOA;;kCACrB,KAACX;wBAAeS,SAASA;wBAASE,OAAOA;wBAAOK,UAAUA;wBAAUC,aAAaA;;kCACjF,KAACd;kCACC,cAAA,KAACD;4BACCO,SAASA;4BACTC,aAAaA;4BACbC,OAAOA;4BACPK,UAAUA;4BACVI,cAAcA;4BACdgB,aAAaf;;;;;YAIlBD,8BACC;;kCACE,KAAChB;wBAAiBiC,WAAWX;wBAAYY,SAASC,SAAS1B,MAAMyB,OAAO,CAACT;wBAAOW,QAAQZ;;kCACxF,KAAC/B;wBAAI4C,OAAO;4BAAEC,OAAO,GAAG,AAAC,CAAA,IAAIf,UAAS,IAAK,IAAI,CAAC,CAAC;wBAAC;wBAAGK,IAAI;4BAAEW,UAAU;wBAAO;kCAC1E,cAAA,KAAC1C;4BACCS,aAAaA;4BACbC,OAAOA;4BACPiC,MAAMxB;4BACNyB,iBAAiB,IAAMxB,gBAAgBI;;;;;;;AAOrD"}
1
+ {"version":3,"sources":["../../../src/TracingGanttChart/TracingGanttChart.tsx"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { ReactElement, useMemo, useRef, useState } from 'react';\nimport { Box, Stack } from '@mui/material';\nimport { otlptracev1 } from '@perses-dev/core';\nimport { CustomLinks, TracingGanttChartOptions } from '../gantt-chart-model';\nimport { MiniGanttChart } from './MiniGanttChart/MiniGanttChart';\nimport { DetailPane } from './DetailPane/DetailPane';\nimport { Viewport } from './utils';\nimport { GanttTable } from './GanttTable/GanttTable';\nimport { GanttTableProvider } from './GanttTable/GanttTableProvider';\nimport { ResizableDivider } from './GanttTable/ResizableDivider';\nimport { getTraceModel, Span } from './trace';\nimport { TraceHeaderBar } from './TraceHeaderBar';\nimport { useSpanSearch } from './Search';\n\nexport interface TracingGanttChartProps {\n options: TracingGanttChartOptions;\n customLinks?: CustomLinks;\n trace: otlptracev1.TracesData;\n}\n\n/**\n * The core GanttChart panel for Perses.\n *\n * The UI/UX of this panel is based on Jaeger UI, licensed under Apache License, Version 2.0.\n * https://github.com/jaegertracing/jaeger-ui\n */\nexport function TracingGanttChart(props: TracingGanttChartProps): ReactElement {\n const { options, customLinks, trace: otlpTrace } = props;\n\n const trace = useMemo(() => {\n try {\n return getTraceModel(otlpTrace);\n } catch (e) {\n throw new Error(`Error: unable to parse trace: ${e}`);\n }\n }, [otlpTrace]);\n const [viewport, setViewport] = useState<Viewport>({\n startTimeUnixMs: trace.startTimeUnixMs,\n endTimeUnixMs: trace.endTimeUnixMs,\n });\n const [selectedSpan, setSelectedSpan] = useState<Span | undefined>(() =>\n options.selectedSpanId ? trace.spanById.get(options.selectedSpanId) : undefined\n );\n const search = useSpanSearch(trace);\n\n const ganttChart = useRef<HTMLDivElement>(null);\n // tableWidth only comes to effect if the detail pane is visible.\n // setTableWidth() is only called by <ResizableDivider />\n const [tableWidth, setTableWidth] = useState<number>(0.82);\n const gap = 2;\n const spacing = ganttChart.current ? parseFloat(getComputedStyle(ganttChart.current).columnGap) || 0 : 0;\n\n return (\n <Stack ref={ganttChart} direction=\"row\" sx={{ height: '100%', minHeight: '240px', gap }}>\n <Stack sx={{ flexGrow: 1, gap }}>\n <TraceHeaderBar trace={trace} search={search} />\n <MiniGanttChart options={options} trace={trace} viewport={viewport} setViewport={setViewport} />\n <GanttTableProvider>\n <GanttTable\n options={options}\n customLinks={customLinks}\n trace={trace}\n viewport={viewport}\n selectedSpan={selectedSpan}\n onSpanClick={setSelectedSpan}\n matchingSpanIds={search.matchingSpanIds}\n focusedSpanId={search.matchingSpanIds[search.focusedMatchIndex]}\n />\n </GanttTableProvider>\n </Stack>\n {selectedSpan && (\n <>\n <ResizableDivider parentRef={ganttChart} spacing={spacing} onMove={setTableWidth} />\n <Box\n style={{\n width: `${(1 - tableWidth) * 100}%`,\n minWidth: `${(1 - tableWidth) * 100}%`,\n }}\n sx={{ overflow: 'auto' }}\n >\n <DetailPane\n customLinks={customLinks}\n trace={trace}\n span={selectedSpan}\n onCloseBtnClick={() => setSelectedSpan(undefined)}\n />\n </Box>\n </>\n )}\n </Stack>\n );\n}\n"],"names":["useMemo","useRef","useState","Box","Stack","MiniGanttChart","DetailPane","GanttTable","GanttTableProvider","ResizableDivider","getTraceModel","TraceHeaderBar","useSpanSearch","TracingGanttChart","props","options","customLinks","trace","otlpTrace","e","Error","viewport","setViewport","startTimeUnixMs","endTimeUnixMs","selectedSpan","setSelectedSpan","selectedSpanId","spanById","get","undefined","search","ganttChart","tableWidth","setTableWidth","gap","spacing","current","parseFloat","getComputedStyle","columnGap","ref","direction","sx","height","minHeight","flexGrow","onSpanClick","matchingSpanIds","focusedSpanId","focusedMatchIndex","parentRef","onMove","style","width","minWidth","overflow","span","onCloseBtnClick"],"mappings":";AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAEjC,SAAuBA,OAAO,EAAEC,MAAM,EAAEC,QAAQ,QAAQ,QAAQ;AAChE,SAASC,GAAG,EAAEC,KAAK,QAAQ,gBAAgB;AAG3C,SAASC,cAAc,QAAQ,kCAAkC;AACjE,SAASC,UAAU,QAAQ,0BAA0B;AAErD,SAASC,UAAU,QAAQ,0BAA0B;AACrD,SAASC,kBAAkB,QAAQ,kCAAkC;AACrE,SAASC,gBAAgB,QAAQ,gCAAgC;AACjE,SAASC,aAAa,QAAc,UAAU;AAC9C,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,aAAa,QAAQ,WAAW;AAQzC;;;;;CAKC,GACD,OAAO,SAASC,kBAAkBC,KAA6B;IAC7D,MAAM,EAAEC,OAAO,EAAEC,WAAW,EAAEC,OAAOC,SAAS,EAAE,GAAGJ;IAEnD,MAAMG,QAAQjB,QAAQ;QACpB,IAAI;YACF,OAAOU,cAAcQ;QACvB,EAAE,OAAOC,GAAG;YACV,MAAM,IAAIC,MAAM,CAAC,8BAA8B,EAAED,GAAG;QACtD;IACF,GAAG;QAACD;KAAU;IACd,MAAM,CAACG,UAAUC,YAAY,GAAGpB,SAAmB;QACjDqB,iBAAiBN,MAAMM,eAAe;QACtCC,eAAeP,MAAMO,aAAa;IACpC;IACA,MAAM,CAACC,cAAcC,gBAAgB,GAAGxB,SAA2B,IACjEa,QAAQY,cAAc,GAAGV,MAAMW,QAAQ,CAACC,GAAG,CAACd,QAAQY,cAAc,IAAIG;IAExE,MAAMC,SAASnB,cAAcK;IAE7B,MAAMe,aAAa/B,OAAuB;IAC1C,iEAAiE;IACjE,yDAAyD;IACzD,MAAM,CAACgC,YAAYC,cAAc,GAAGhC,SAAiB;IACrD,MAAMiC,MAAM;IACZ,MAAMC,UAAUJ,WAAWK,OAAO,GAAGC,WAAWC,iBAAiBP,WAAWK,OAAO,EAAEG,SAAS,KAAK,IAAI;IAEvG,qBACE,MAACpC;QAAMqC,KAAKT;QAAYU,WAAU;QAAMC,IAAI;YAAEC,QAAQ;YAAQC,WAAW;YAASV;QAAI;;0BACpF,MAAC/B;gBAAMuC,IAAI;oBAAEG,UAAU;oBAAGX;gBAAI;;kCAC5B,KAACxB;wBAAeM,OAAOA;wBAAOc,QAAQA;;kCACtC,KAAC1B;wBAAeU,SAASA;wBAASE,OAAOA;wBAAOI,UAAUA;wBAAUC,aAAaA;;kCACjF,KAACd;kCACC,cAAA,KAACD;4BACCQ,SAASA;4BACTC,aAAaA;4BACbC,OAAOA;4BACPI,UAAUA;4BACVI,cAAcA;4BACdsB,aAAarB;4BACbsB,iBAAiBjB,OAAOiB,eAAe;4BACvCC,eAAelB,OAAOiB,eAAe,CAACjB,OAAOmB,iBAAiB,CAAC;;;;;YAIpEzB,8BACC;;kCACE,KAAChB;wBAAiB0C,WAAWnB;wBAAYI,SAASA;wBAASgB,QAAQlB;;kCACnE,KAAC/B;wBACCkD,OAAO;4BACLC,OAAO,GAAG,AAAC,CAAA,IAAIrB,UAAS,IAAK,IAAI,CAAC,CAAC;4BACnCsB,UAAU,GAAG,AAAC,CAAA,IAAItB,UAAS,IAAK,IAAI,CAAC,CAAC;wBACxC;wBACAU,IAAI;4BAAEa,UAAU;wBAAO;kCAEvB,cAAA,KAAClD;4BACCU,aAAaA;4BACbC,OAAOA;4BACPwC,MAAMhC;4BACNiC,iBAAiB,IAAMhC,gBAAgBI;;;;;;;AAOrD"}
@@ -49,4 +49,9 @@ export interface Link {
49
49
  * Time complexity: O(2n)
50
50
  */
51
51
  export declare function getTraceModel(trace: otlptracev1.TracesData): Trace;
52
+ /**
53
+ * Recursively iterates all spans depth-first.
54
+ * Return false from the callback to skip a span's children.
55
+ */
56
+ export declare function forEachSpan(spans: Span[], fn: (span: Span) => boolean | void): void;
52
57
  //# sourceMappingURL=trace.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/TracingGanttChart/trace.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAkB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG7E,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;IAE9B;;;OAGG;IACH,SAAS,EAAE,IAAI,EAAE,CAAC;IAClB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC,oBAAoB,CAAC;IACzC,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,uCAAuC;IACvC,UAAU,EAAE,IAAI,EAAE,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;IACpC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,KAAK;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,UAAU,GAAG,KAAK,CAmDlE"}
1
+ {"version":3,"file":"trace.d.ts","sourceRoot":"","sources":["../../../src/TracingGanttChart/trace.ts"],"names":[],"mappings":"AAaA,OAAO,EAAE,YAAY,EAAkB,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG7E,2EAA2E;AAC3E,MAAM,WAAW,KAAK;IACpB,KAAK,EAAE,WAAW,CAAC,UAAU,CAAC;IAE9B;;;OAGG;IACH,SAAS,EAAE,IAAI,EAAE,CAAC;IAClB,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAC5B,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,KAAK,EAAE,YAAY,CAAC,oBAAoB,CAAC;IACzC,UAAU,CAAC,EAAE,IAAI,CAAC;IAClB,uCAAuC;IACvC,UAAU,EAAE,IAAI,EAAE,CAAC;IAEnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,MAAM,CAAC;IACxB,aAAa,EAAE,MAAM,CAAC;IACtB,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;IACpC,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,MAAM,EAAE,WAAW,CAAC,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,QAAQ;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,KAAK;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;CACrC;AAED,MAAM,WAAW,IAAI;IACnB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,YAAY,CAAC,QAAQ,EAAE,CAAC;CACrC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,CAAC,UAAU,GAAG,KAAK,CAmDlE;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,GAAG,IAAI,GAAG,IAAI,CAMnF"}
@@ -66,6 +66,16 @@ import { sortedIndexBy } from 'lodash';
66
66
  endTimeUnixMs
67
67
  };
68
68
  }
69
+ /**
70
+ * Recursively iterates all spans depth-first.
71
+ * Return false from the callback to skip a span's children.
72
+ */ export function forEachSpan(spans, fn) {
73
+ for (const span of spans){
74
+ if (fn(span) !== false) {
75
+ forEachSpan(span.childSpans, fn);
76
+ }
77
+ }
78
+ }
69
79
  function parseResource(resource) {
70
80
  let serviceName = 'unknown';
71
81
  for (const attr of resource?.attributes ?? []){
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/TracingGanttChart/trace.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { otlpcommonv1, otlpresourcev1, otlptracev1 } from '@perses-dev/core';\nimport { sortedIndexBy } from 'lodash';\n\n/** holds the trace and computed properties required for the Gantt chart */\nexport interface Trace {\n trace: otlptracev1.TracesData;\n\n /**\n * if a trace is incomplete (e.g. a parent span has not been received yet),\n * this branch of the span tree will be appended to the root\n */\n rootSpans: Span[];\n spanById: Map<string, Span>;\n startTimeUnixMs: number;\n endTimeUnixMs: number;\n}\n\nexport interface Span {\n resource: Resource;\n scope: otlpcommonv1.InstrumentationScope;\n parentSpan?: Span;\n /** child spans, sorted by startTime */\n childSpans: Span[];\n\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n kind?: string;\n startTimeUnixMs: number;\n endTimeUnixMs: number;\n attributes: otlpcommonv1.KeyValue[];\n events: Event[];\n links: Link[];\n status: otlptracev1.Status;\n}\n\nexport interface Resource {\n serviceName?: string;\n attributes: otlpcommonv1.KeyValue[];\n}\n\nexport interface Event {\n timeUnixMs: number;\n name: string;\n attributes: otlpcommonv1.KeyValue[];\n}\n\nexport interface Link {\n traceId: string;\n spanId: string;\n attributes: otlpcommonv1.KeyValue[];\n}\n\n/**\n * getTraceModel builds a tree of spans from an OTLP trace,\n * and precomputes common fields, for example the start and end time of a trace.\n * Time complexity: O(2n)\n */\nexport function getTraceModel(trace: otlptracev1.TracesData): Trace {\n // first pass: build lookup table <spanId, Span> and compute min/max\n const spanById = new Map<string, Span>();\n const rootSpans: Span[] = [];\n let startTimeUnixMs: number = 0;\n let endTimeUnixMs: number = 0;\n for (const resourceSpan of trace.resourceSpans) {\n const resource = parseResource(resourceSpan.resource);\n\n for (const scopeSpan of resourceSpan.scopeSpans) {\n const scope = parseScope(scopeSpan.scope);\n\n for (const otelSpan of scopeSpan.spans) {\n const span: Span = {\n resource,\n scope,\n childSpans: [],\n ...parseSpan(otelSpan),\n };\n spanById.set(otelSpan.spanId, span);\n\n if (startTimeUnixMs === 0 || span.startTimeUnixMs < startTimeUnixMs) {\n startTimeUnixMs = span.startTimeUnixMs;\n }\n if (endTimeUnixMs === 0 || span.endTimeUnixMs > endTimeUnixMs) {\n endTimeUnixMs = span.endTimeUnixMs;\n }\n }\n }\n }\n\n // second pass: build tree based on parentSpanId property\n for (const [, span] of spanById) {\n if (!span.parentSpanId) {\n rootSpans.push(span);\n continue;\n }\n\n const parent = spanById.get(span.parentSpanId);\n if (!parent) {\n console.trace(`span ${span.spanId} has parent ${span.parentSpanId} which has not been received yet`);\n rootSpans.push(span);\n continue;\n }\n\n span.parentSpan = parent;\n const insertChildSpanAt = sortedIndexBy(parent.childSpans, span, (s) => s.startTimeUnixMs);\n parent.childSpans.splice(insertChildSpanAt, 0, span);\n }\n\n return { trace, rootSpans, spanById, startTimeUnixMs, endTimeUnixMs };\n}\n\nfunction parseResource(resource?: otlpresourcev1.Resource): Resource {\n let serviceName = 'unknown';\n for (const attr of resource?.attributes ?? []) {\n if (attr.key === 'service.name' && 'stringValue' in attr.value) {\n serviceName = attr.value.stringValue;\n break;\n }\n }\n\n return {\n serviceName,\n attributes: resource?.attributes ?? [],\n };\n}\n\nfunction parseScope(scope?: otlpcommonv1.InstrumentationScope): otlpcommonv1.InstrumentationScope {\n return scope ?? {};\n}\n\n/**\n * parseSpan parses the Span API type to the internal representation\n * i.e. convert strings to numbers etc.\n */\nfunction parseSpan(span: otlptracev1.Span): Omit<Span, 'resource' | 'scope' | 'childSpans'> {\n return {\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n kind: span.kind,\n startTimeUnixMs: parseInt(span.startTimeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n endTimeUnixMs: parseInt(span.endTimeUnixNano) * 1e-6,\n attributes: span.attributes ?? [],\n events: (span.events ?? []).map(parseEvent),\n links: (span.links ?? []).map(parseLink),\n status: span.status ?? {},\n };\n}\n\nfunction parseEvent(event: otlptracev1.Event): Event {\n return {\n timeUnixMs: parseInt(event.timeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n name: event.name,\n attributes: event.attributes ?? [],\n };\n}\n\nfunction parseLink(link: otlptracev1.Link): Link {\n return {\n traceId: link.traceId,\n spanId: link.spanId,\n attributes: link.attributes ?? [],\n };\n}\n"],"names":["sortedIndexBy","getTraceModel","trace","spanById","Map","rootSpans","startTimeUnixMs","endTimeUnixMs","resourceSpan","resourceSpans","resource","parseResource","scopeSpan","scopeSpans","scope","parseScope","otelSpan","spans","span","childSpans","parseSpan","set","spanId","parentSpanId","push","parent","get","console","parentSpan","insertChildSpanAt","s","splice","serviceName","attr","attributes","key","value","stringValue","traceId","name","kind","parseInt","startTimeUnixNano","endTimeUnixNano","events","map","parseEvent","links","parseLink","status","event","timeUnixMs","timeUnixNano","link"],"mappings":"AAAA,+BAA+B;AAC/B,kEAAkE;AAClE,mEAAmE;AACnE,0CAA0C;AAC1C,EAAE;AACF,6CAA6C;AAC7C,EAAE;AACF,sEAAsE;AACtE,oEAAoE;AACpE,2EAA2E;AAC3E,sEAAsE;AACtE,iCAAiC;AAGjC,SAASA,aAAa,QAAQ,SAAS;AAqDvC;;;;CAIC,GACD,OAAO,SAASC,cAAcC,KAA6B;IACzD,oEAAoE;IACpE,MAAMC,WAAW,IAAIC;IACrB,MAAMC,YAAoB,EAAE;IAC5B,IAAIC,kBAA0B;IAC9B,IAAIC,gBAAwB;IAC5B,KAAK,MAAMC,gBAAgBN,MAAMO,aAAa,CAAE;QAC9C,MAAMC,WAAWC,cAAcH,aAAaE,QAAQ;QAEpD,KAAK,MAAME,aAAaJ,aAAaK,UAAU,CAAE;YAC/C,MAAMC,QAAQC,WAAWH,UAAUE,KAAK;YAExC,KAAK,MAAME,YAAYJ,UAAUK,KAAK,CAAE;gBACtC,MAAMC,OAAa;oBACjBR;oBACAI;oBACAK,YAAY,EAAE;oBACd,GAAGC,UAAUJ,SAAS;gBACxB;gBACAb,SAASkB,GAAG,CAACL,SAASM,MAAM,EAAEJ;gBAE9B,IAAIZ,oBAAoB,KAAKY,KAAKZ,eAAe,GAAGA,iBAAiB;oBACnEA,kBAAkBY,KAAKZ,eAAe;gBACxC;gBACA,IAAIC,kBAAkB,KAAKW,KAAKX,aAAa,GAAGA,eAAe;oBAC7DA,gBAAgBW,KAAKX,aAAa;gBACpC;YACF;QACF;IACF;IAEA,yDAAyD;IACzD,KAAK,MAAM,GAAGW,KAAK,IAAIf,SAAU;QAC/B,IAAI,CAACe,KAAKK,YAAY,EAAE;YACtBlB,UAAUmB,IAAI,CAACN;YACf;QACF;QAEA,MAAMO,SAAStB,SAASuB,GAAG,CAACR,KAAKK,YAAY;QAC7C,IAAI,CAACE,QAAQ;YACXE,QAAQzB,KAAK,CAAC,CAAC,KAAK,EAAEgB,KAAKI,MAAM,CAAC,YAAY,EAAEJ,KAAKK,YAAY,CAAC,gCAAgC,CAAC;YACnGlB,UAAUmB,IAAI,CAACN;YACf;QACF;QAEAA,KAAKU,UAAU,GAAGH;QAClB,MAAMI,oBAAoB7B,cAAcyB,OAAON,UAAU,EAAED,MAAM,CAACY,IAAMA,EAAExB,eAAe;QACzFmB,OAAON,UAAU,CAACY,MAAM,CAACF,mBAAmB,GAAGX;IACjD;IAEA,OAAO;QAAEhB;QAAOG;QAAWF;QAAUG;QAAiBC;IAAc;AACtE;AAEA,SAASI,cAAcD,QAAkC;IACvD,IAAIsB,cAAc;IAClB,KAAK,MAAMC,QAAQvB,UAAUwB,cAAc,EAAE,CAAE;QAC7C,IAAID,KAAKE,GAAG,KAAK,kBAAkB,iBAAiBF,KAAKG,KAAK,EAAE;YAC9DJ,cAAcC,KAAKG,KAAK,CAACC,WAAW;YACpC;QACF;IACF;IAEA,OAAO;QACLL;QACAE,YAAYxB,UAAUwB,cAAc,EAAE;IACxC;AACF;AAEA,SAASnB,WAAWD,KAAyC;IAC3D,OAAOA,SAAS,CAAC;AACnB;AAEA;;;CAGC,GACD,SAASM,UAAUF,IAAsB;IACvC,OAAO;QACLoB,SAASpB,KAAKoB,OAAO;QACrBhB,QAAQJ,KAAKI,MAAM;QACnBC,cAAcL,KAAKK,YAAY;QAC/BgB,MAAMrB,KAAKqB,IAAI;QACfC,MAAMtB,KAAKsB,IAAI;QACflC,iBAAiBmC,SAASvB,KAAKwB,iBAAiB,IAAI;QACpDnC,eAAekC,SAASvB,KAAKyB,eAAe,IAAI;QAChDT,YAAYhB,KAAKgB,UAAU,IAAI,EAAE;QACjCU,QAAQ,AAAC1B,CAAAA,KAAK0B,MAAM,IAAI,EAAE,AAAD,EAAGC,GAAG,CAACC;QAChCC,OAAO,AAAC7B,CAAAA,KAAK6B,KAAK,IAAI,EAAE,AAAD,EAAGF,GAAG,CAACG;QAC9BC,QAAQ/B,KAAK+B,MAAM,IAAI,CAAC;IAC1B;AACF;AAEA,SAASH,WAAWI,KAAwB;IAC1C,OAAO;QACLC,YAAYV,SAASS,MAAME,YAAY,IAAI;QAC3Cb,MAAMW,MAAMX,IAAI;QAChBL,YAAYgB,MAAMhB,UAAU,IAAI,EAAE;IACpC;AACF;AAEA,SAASc,UAAUK,IAAsB;IACvC,OAAO;QACLf,SAASe,KAAKf,OAAO;QACrBhB,QAAQ+B,KAAK/B,MAAM;QACnBY,YAAYmB,KAAKnB,UAAU,IAAI,EAAE;IACnC;AACF"}
1
+ {"version":3,"sources":["../../../src/TracingGanttChart/trace.ts"],"sourcesContent":["// Copyright The Perses Authors\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not use this file except in compliance with the License.\n// You may obtain a copy of the License at\n//\n// http://www.apache.org/licenses/LICENSE-2.0\n//\n// Unless required by applicable law or agreed to in writing, software\n// distributed under the License is distributed on an \"AS IS\" BASIS,\n// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n// See the License for the specific language governing permissions and\n// limitations under the License.\n\nimport { otlpcommonv1, otlpresourcev1, otlptracev1 } from '@perses-dev/core';\nimport { sortedIndexBy } from 'lodash';\n\n/** holds the trace and computed properties required for the Gantt chart */\nexport interface Trace {\n trace: otlptracev1.TracesData;\n\n /**\n * if a trace is incomplete (e.g. a parent span has not been received yet),\n * this branch of the span tree will be appended to the root\n */\n rootSpans: Span[];\n spanById: Map<string, Span>;\n startTimeUnixMs: number;\n endTimeUnixMs: number;\n}\n\nexport interface Span {\n resource: Resource;\n scope: otlpcommonv1.InstrumentationScope;\n parentSpan?: Span;\n /** child spans, sorted by startTime */\n childSpans: Span[];\n\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n kind?: string;\n startTimeUnixMs: number;\n endTimeUnixMs: number;\n attributes: otlpcommonv1.KeyValue[];\n events: Event[];\n links: Link[];\n status: otlptracev1.Status;\n}\n\nexport interface Resource {\n serviceName?: string;\n attributes: otlpcommonv1.KeyValue[];\n}\n\nexport interface Event {\n timeUnixMs: number;\n name: string;\n attributes: otlpcommonv1.KeyValue[];\n}\n\nexport interface Link {\n traceId: string;\n spanId: string;\n attributes: otlpcommonv1.KeyValue[];\n}\n\n/**\n * getTraceModel builds a tree of spans from an OTLP trace,\n * and precomputes common fields, for example the start and end time of a trace.\n * Time complexity: O(2n)\n */\nexport function getTraceModel(trace: otlptracev1.TracesData): Trace {\n // first pass: build lookup table <spanId, Span> and compute min/max\n const spanById = new Map<string, Span>();\n const rootSpans: Span[] = [];\n let startTimeUnixMs: number = 0;\n let endTimeUnixMs: number = 0;\n for (const resourceSpan of trace.resourceSpans) {\n const resource = parseResource(resourceSpan.resource);\n\n for (const scopeSpan of resourceSpan.scopeSpans) {\n const scope = parseScope(scopeSpan.scope);\n\n for (const otelSpan of scopeSpan.spans) {\n const span: Span = {\n resource,\n scope,\n childSpans: [],\n ...parseSpan(otelSpan),\n };\n spanById.set(otelSpan.spanId, span);\n\n if (startTimeUnixMs === 0 || span.startTimeUnixMs < startTimeUnixMs) {\n startTimeUnixMs = span.startTimeUnixMs;\n }\n if (endTimeUnixMs === 0 || span.endTimeUnixMs > endTimeUnixMs) {\n endTimeUnixMs = span.endTimeUnixMs;\n }\n }\n }\n }\n\n // second pass: build tree based on parentSpanId property\n for (const [, span] of spanById) {\n if (!span.parentSpanId) {\n rootSpans.push(span);\n continue;\n }\n\n const parent = spanById.get(span.parentSpanId);\n if (!parent) {\n console.trace(`span ${span.spanId} has parent ${span.parentSpanId} which has not been received yet`);\n rootSpans.push(span);\n continue;\n }\n\n span.parentSpan = parent;\n const insertChildSpanAt = sortedIndexBy(parent.childSpans, span, (s) => s.startTimeUnixMs);\n parent.childSpans.splice(insertChildSpanAt, 0, span);\n }\n\n return { trace, rootSpans, spanById, startTimeUnixMs, endTimeUnixMs };\n}\n\n/**\n * Recursively iterates all spans depth-first.\n * Return false from the callback to skip a span's children.\n */\nexport function forEachSpan(spans: Span[], fn: (span: Span) => boolean | void): void {\n for (const span of spans) {\n if (fn(span) !== false) {\n forEachSpan(span.childSpans, fn);\n }\n }\n}\n\nfunction parseResource(resource?: otlpresourcev1.Resource): Resource {\n let serviceName = 'unknown';\n for (const attr of resource?.attributes ?? []) {\n if (attr.key === 'service.name' && 'stringValue' in attr.value) {\n serviceName = attr.value.stringValue;\n break;\n }\n }\n\n return {\n serviceName,\n attributes: resource?.attributes ?? [],\n };\n}\n\nfunction parseScope(scope?: otlpcommonv1.InstrumentationScope): otlpcommonv1.InstrumentationScope {\n return scope ?? {};\n}\n\n/**\n * parseSpan parses the Span API type to the internal representation\n * i.e. convert strings to numbers etc.\n */\nfunction parseSpan(span: otlptracev1.Span): Omit<Span, 'resource' | 'scope' | 'childSpans'> {\n return {\n traceId: span.traceId,\n spanId: span.spanId,\n parentSpanId: span.parentSpanId,\n name: span.name,\n kind: span.kind,\n startTimeUnixMs: parseInt(span.startTimeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n endTimeUnixMs: parseInt(span.endTimeUnixNano) * 1e-6,\n attributes: span.attributes ?? [],\n events: (span.events ?? []).map(parseEvent),\n links: (span.links ?? []).map(parseLink),\n status: span.status ?? {},\n };\n}\n\nfunction parseEvent(event: otlptracev1.Event): Event {\n return {\n timeUnixMs: parseInt(event.timeUnixNano) * 1e-6, // convert to milliseconds because JS cannot handle numbers larger than 9007199254740991\n name: event.name,\n attributes: event.attributes ?? [],\n };\n}\n\nfunction parseLink(link: otlptracev1.Link): Link {\n return {\n traceId: link.traceId,\n spanId: link.spanId,\n attributes: link.attributes ?? [],\n };\n}\n"],"names":["sortedIndexBy","getTraceModel","trace","spanById","Map","rootSpans","startTimeUnixMs","endTimeUnixMs","resourceSpan","resourceSpans","resource","parseResource","scopeSpan","scopeSpans","scope","parseScope","otelSpan","spans","span","childSpans","parseSpan","set","spanId","parentSpanId","push","parent","get","console","parentSpan","insertChildSpanAt","s","splice","forEachSpan","fn","serviceName","attr","attributes","key","value","stringValue","traceId","name","kind","parseInt","startTimeUnixNano","endTimeUnixNano","events","map","parseEvent","links","parseLink","status","event","timeUnixMs","timeUnixNano","link"],"mappings":"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"}
@@ -32,6 +32,9 @@ _export(exports, {
32
32
  },
33
33
  get TraceAttributes () {
34
34
  return TraceAttributes;
35
+ },
36
+ get renderAttributeValue () {
37
+ return renderAttributeValue;
35
38
  }
36
39
  });
37
40
  const _jsxruntime = require("react/jsx-runtime");
@@ -56,22 +59,59 @@ function TraceAttributes(props) {
56
59
  /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItem, {
57
60
  name: "duration",
58
61
  value: (0, _utils.formatDuration)(span.endTimeUnixMs - span.startTimeUnixMs)
62
+ }),
63
+ span.kind && /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItem, {
64
+ name: "kind",
65
+ value: span.kind
66
+ }),
67
+ span.status.code && /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItem, {
68
+ name: "status code",
69
+ value: span.status.code
70
+ }),
71
+ span.status.message && /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItem, {
72
+ name: "status message",
73
+ value: span.status.message
59
74
  })
60
75
  ]
61
76
  }),
62
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {}),
63
77
  span.attributes.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
64
78
  children: [
79
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {}),
65
80
  /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeList, {
66
81
  customLinks: customLinks,
67
82
  attributes: span.attributes.toSorted((a, b)=>a.key.localeCompare(b.key))
68
- }),
69
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {})
83
+ })
70
84
  ]
71
85
  }),
72
- /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeList, {
73
- customLinks: customLinks,
74
- attributes: span.resource.attributes.toSorted((a, b)=>a.key.localeCompare(b.key))
86
+ span.resource.attributes.length > 0 && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
87
+ children: [
88
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {}),
89
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeList, {
90
+ customLinks: customLinks,
91
+ attributes: span.resource.attributes.toSorted((a, b)=>a.key.localeCompare(b.key))
92
+ })
93
+ ]
94
+ }),
95
+ (span.scope.name || span.scope.version || span.scope.attributes && span.scope.attributes.length > 0) && /*#__PURE__*/ (0, _jsxruntime.jsxs)(_jsxruntime.Fragment, {
96
+ children: [
97
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Divider, {}),
98
+ /*#__PURE__*/ (0, _jsxruntime.jsxs)(_material.List, {
99
+ children: [
100
+ span.scope.name && /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItem, {
101
+ name: "scope name",
102
+ value: span.scope.name
103
+ }),
104
+ span.scope.version && /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItem, {
105
+ name: "scope version",
106
+ value: span.scope.version
107
+ }),
108
+ /*#__PURE__*/ (0, _jsxruntime.jsx)(AttributeItems, {
109
+ customLinks: customLinks,
110
+ attributes: (span.scope.attributes ?? []).toSorted((a, b)=>a.key.localeCompare(b.key))
111
+ })
112
+ ]
113
+ })
114
+ ]
75
115
  })
76
116
  ]
77
117
  });
@@ -160,5 +200,5 @@ function renderAttributeValue(value) {
160
200
  const values = value.arrayValue.values;
161
201
  return values && values.length > 0 ? values.map(renderAttributeValue).join(', ') : '<empty array>';
162
202
  }
163
- return 'unknown';
203
+ return '<unknown type>';
164
204
  }
@@ -24,34 +24,81 @@ const _jsxruntime = require("react/jsx-runtime");
24
24
  const _reactvirtuoso = require("react-virtuoso");
25
25
  const _react = require("react");
26
26
  const _material = require("@mui/material");
27
+ const _trace = require("../trace");
27
28
  const _GanttTableProvider = require("./GanttTableProvider");
28
29
  const _GanttTableRow = require("./GanttTableRow");
29
30
  const _GanttTableHeader = require("./GanttTableHeader");
30
31
  const _ResizableDivider = require("./ResizableDivider");
31
32
  function GanttTable(props) {
32
- const { options, customLinks, trace, viewport, selectedSpan, onSpanClick } = props;
33
- const { collapsedSpans, setVisibleSpans } = (0, _GanttTableProvider.useGanttTableContext)();
33
+ const { options, customLinks, trace, viewport, selectedSpan, onSpanClick, matchingSpanIds, focusedSpanId } = props;
34
+ const { collapsedSpans, setCollapsedSpans, setVisibleSpans } = (0, _GanttTableProvider.useGanttTableContext)();
34
35
  const [nameColumnWidth, setNameColumnWidth] = (0, _react.useState)(0.25);
35
36
  const tableRef = (0, _react.useRef)(null);
37
+ const virtuosoRef = (0, _react.useRef)(null);
36
38
  const theme = (0, _material.useTheme)();
39
+ // Recursively flatten the span tree to a list of rows, hiding collapsed child spans.
37
40
  const rows = (0, _react.useMemo)(()=>{
38
41
  const rows = [];
39
- for (const rootSpan of trace.rootSpans){
40
- treeToRows(rows, rootSpan, collapsedSpans);
41
- }
42
+ (0, _trace.forEachSpan)(trace.rootSpans, (span)=>{
43
+ rows.push(span);
44
+ if (collapsedSpans.has(span.spanId)) {
45
+ return false;
46
+ }
47
+ });
42
48
  return rows;
43
49
  }, [
44
50
  trace.rootSpans,
45
51
  collapsedSpans
46
52
  ]);
47
- const selectedSpanIndex = (0, _react.useMemo)(()=>{
48
- if (!selectedSpan) return undefined;
49
- for(let i = 0; i < rows.length; i++){
50
- if (rows[i]?.spanId === selectedSpan.spanId) {
51
- return i;
52
- }
53
+ const matchingSpanIdSet = (0, _react.useMemo)(()=>new Set(matchingSpanIds ?? []), [
54
+ matchingSpanIds
55
+ ]);
56
+ // Auto-expand collapsed ancestors when focusing a search match
57
+ (0, _react.useEffect)(()=>{
58
+ if (!focusedSpanId) return;
59
+ const span = trace.spanById.get(focusedSpanId);
60
+ if (!span) return;
61
+ const ancestorIds = new Set();
62
+ let parent = span.parentSpan;
63
+ while(parent){
64
+ ancestorIds.add(parent.spanId);
65
+ parent = parent.parentSpan;
66
+ }
67
+ if (ancestorIds.size > 0) {
68
+ setCollapsedSpans((prev)=>{
69
+ const next = new Set(prev);
70
+ let changed = false;
71
+ for (const id of ancestorIds){
72
+ if (next.delete(id)) changed = true;
73
+ }
74
+ return changed ? next : prev;
75
+ });
53
76
  }
54
- return undefined;
77
+ }, [
78
+ focusedSpanId,
79
+ trace.spanById,
80
+ setCollapsedSpans
81
+ ]);
82
+ // Scroll to focused span when using prev/next buttons in search bar.
83
+ (0, _react.useEffect)(()=>{
84
+ if (!focusedSpanId || !virtuosoRef.current) return;
85
+ const index = rows.findIndex((r)=>r.spanId === focusedSpanId);
86
+ if (index >= 0) {
87
+ virtuosoRef.current.scrollToIndex({
88
+ index,
89
+ align: 'center'
90
+ });
91
+ }
92
+ }, [
93
+ focusedSpanId,
94
+ rows
95
+ ]);
96
+ // Set the top most index in the Virtuoso table to the selected span
97
+ // Required e.g. when navigating from another page.
98
+ const initialTopMostSpanIndex = (0, _react.useMemo)(()=>{
99
+ if (!selectedSpan) return 0;
100
+ const index = rows.findIndex((r)=>r.spanId === selectedSpan.spanId);
101
+ return index >= 0 ? index : 0;
55
102
  }, [
56
103
  rows,
57
104
  selectedSpan
@@ -85,14 +132,17 @@ function GanttTable(props) {
85
132
  divider: divider
86
133
  }),
87
134
  /*#__PURE__*/ (0, _jsxruntime.jsx)(_reactvirtuoso.Virtuoso, {
135
+ ref: virtuosoRef,
88
136
  data: rows,
89
- initialTopMostItemIndex: selectedSpanIndex ?? 0,
137
+ initialTopMostItemIndex: initialTopMostSpanIndex,
90
138
  itemContent: (_, span)=>/*#__PURE__*/ (0, _jsxruntime.jsx)(_GanttTableRow.GanttTableRow, {
91
139
  options: options,
92
140
  customLinks: customLinks,
93
141
  span: span,
94
142
  viewport: viewport,
95
143
  selected: span === selectedSpan,
144
+ matched: matchingSpanIdSet.has(span.spanId),
145
+ focused: span.spanId === focusedSpanId,
96
146
  nameColumnWidth: nameColumnWidth,
97
147
  divider: divider,
98
148
  onClick: onSpanClick
@@ -102,14 +152,3 @@ function GanttTable(props) {
102
152
  ]
103
153
  });
104
154
  }
105
- /**
106
- * treeToRows recursively transforms the span tree to a list of rows and
107
- * hides collapsed child spans.
108
- */ function treeToRows(rows, span, collapsedSpans) {
109
- rows.push(span);
110
- if (!collapsedSpans.includes(span.spanId)) {
111
- for (const child of span.childSpans){
112
- treeToRows(rows, child, collapsedSpans);
113
- }
114
- }
115
- }
@@ -36,7 +36,7 @@ const _react = require("react");
36
36
  const GanttTableContext = /*#__PURE__*/ (0, _react.createContext)(undefined);
37
37
  function GanttTableProvider(props) {
38
38
  const { children } = props;
39
- const [collapsedSpans, setCollapsedSpans] = (0, _react.useState)([]);
39
+ const [collapsedSpans, setCollapsedSpans] = (0, _react.useState)(new Set());
40
40
  const [visibleSpans, setVisibleSpans] = (0, _react.useState)([]);
41
41
  const [hoveredParent, setHoveredParent] = (0, _react.useState)(undefined);
42
42
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(GanttTableContext.Provider, {
@@ -27,16 +27,28 @@ const _utils = require("../utils");
27
27
  const _SpanName = require("./SpanName");
28
28
  const _SpanDuration = require("./SpanDuration");
29
29
  const GanttTableRow = /*#__PURE__*/ (0, _react.memo)(function GanttTableRow(props) {
30
- const { options, customLinks, span, viewport, selected, nameColumnWidth, divider, onClick } = props;
30
+ const { options, customLinks, span, viewport, selected, matched, focused, nameColumnWidth, divider, onClick } = props;
31
31
  const theme = (0, _material.useTheme)();
32
32
  const handleOnClick = ()=>{
33
33
  // ignore event if triggered by selecting text
34
34
  if (document.getSelection()?.type === 'Range') return;
35
35
  onClick(span);
36
36
  };
37
+ let backgroundColor;
38
+ if (selected) {
39
+ backgroundColor = theme.palette.action.focus;
40
+ } else if (focused) {
41
+ backgroundColor = theme.palette.action.selected;
42
+ } else if (matched) {
43
+ backgroundColor = theme.palette.action.hover;
44
+ }
37
45
  return /*#__PURE__*/ (0, _jsxruntime.jsxs)(RowContainer, {
38
46
  sx: {
39
- backgroundColor: selected ? theme.palette.action.selected : 'inherit'
47
+ backgroundColor,
48
+ // overwrite hover if background color is set (selected, focused or matched)
49
+ '&:hover': backgroundColor ? {
50
+ backgroundColor
51
+ } : undefined
40
52
  },
41
53
  direction: "row",
42
54
  onClick: handleOnClick,
@@ -35,8 +35,11 @@ function ResizableDivider(props) {
35
35
  // need stable reference for window.removeEventListener() in useEffect() below
36
36
  const handleMouseMove = (0, _pluginsystem.useEvent)((e)=>{
37
37
  if (!parentRef.current) return;
38
- const offsetX = e.clientX - parentRef.current.getBoundingClientRect().left + spacing;
39
- const leftPercent = offsetX / parentRef.current.getBoundingClientRect().width;
38
+ const parentRect = parentRef.current.getBoundingClientRect();
39
+ // The parent can be a flex row, for example: [leftPercent] [gap] [divider] [gap] [1-leftPercent].
40
+ // Without considering spacing, leftPercent would be wrong because it ignores the flex gap between the divider and the element.
41
+ const offsetX = e.clientX - parentRect.left + spacing;
42
+ const leftPercent = offsetX / parentRect.width;
40
43
  if (0.05 <= leftPercent && leftPercent <= 0.95) {
41
44
  onMove(leftPercent);
42
45
  }
@@ -78,6 +81,7 @@ function ResizableDivider(props) {
78
81
  const ResizableDividerBox = (0, _material.styled)(_material.Box)(({ theme })=>({
79
82
  position: 'relative',
80
83
  width: '1px',
84
+ minWidth: '1px',
81
85
  height: '100%',
82
86
  backgroundColor: theme.palette.divider,
83
87
  cursor: 'col-resize',