@perses-dev/logs-table-plugin 0.2.1 → 0.3.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 (240) hide show
  1. package/__mf/css/async/5369.85c2cbf6.css +1 -0
  2. package/__mf/css/async/__federation_expose_LogsTable.eedb54d8.css +1 -0
  3. package/__mf/font/inter-cyrillic-300-normal.432f2b21.woff +0 -0
  4. package/__mf/font/inter-cyrillic-300-normal.9da91009.woff2 +0 -0
  5. package/__mf/font/inter-cyrillic-400-normal.372704ff.woff2 +0 -0
  6. package/__mf/font/inter-cyrillic-400-normal.a6b6ef6f.woff +0 -0
  7. package/__mf/font/inter-cyrillic-500-normal.7c15bba8.woff2 +0 -0
  8. package/__mf/font/inter-cyrillic-500-normal.b9f8c929.woff +0 -0
  9. package/__mf/font/inter-cyrillic-600-normal.2f42892a.woff2 +0 -0
  10. package/__mf/font/inter-cyrillic-600-normal.c3987adc.woff +0 -0
  11. package/__mf/font/inter-cyrillic-700-normal.93eba3c3.woff +0 -0
  12. package/__mf/font/inter-cyrillic-700-normal.e9e5b2dc.woff2 +0 -0
  13. package/__mf/font/inter-cyrillic-900-normal.f285bd7a.woff2 +0 -0
  14. package/__mf/font/inter-cyrillic-900-normal.ffbd8a3a.woff +0 -0
  15. package/__mf/font/inter-cyrillic-ext-300-normal.95bb9038.woff2 +0 -0
  16. package/__mf/font/inter-cyrillic-ext-300-normal.cfc143a9.woff +0 -0
  17. package/__mf/font/inter-cyrillic-ext-400-normal.2a31c04b.woff +0 -0
  18. package/__mf/font/inter-cyrillic-ext-400-normal.f572b170.woff2 +0 -0
  19. package/__mf/font/inter-cyrillic-ext-500-normal.5a6bb1da.woff +0 -0
  20. package/__mf/font/inter-cyrillic-ext-500-normal.fe0d9b14.woff2 +0 -0
  21. package/__mf/font/inter-cyrillic-ext-600-normal.ecbdecad.woff +0 -0
  22. package/__mf/font/inter-cyrillic-ext-600-normal.f7b3c15b.woff2 +0 -0
  23. package/__mf/font/inter-cyrillic-ext-700-normal.4b4022a6.woff +0 -0
  24. package/__mf/font/inter-cyrillic-ext-700-normal.74b516d2.woff2 +0 -0
  25. package/__mf/font/inter-cyrillic-ext-900-normal.9970ddb5.woff +0 -0
  26. package/__mf/font/inter-cyrillic-ext-900-normal.a0d59adc.woff2 +0 -0
  27. package/__mf/font/inter-greek-300-normal.0d7be683.woff2 +0 -0
  28. package/__mf/font/inter-greek-300-normal.8f0b988e.woff +0 -0
  29. package/__mf/font/inter-greek-400-normal.cc58c11b.woff +0 -0
  30. package/__mf/font/inter-greek-400-normal.d7020e3c.woff2 +0 -0
  31. package/__mf/font/inter-greek-500-normal.d9a33207.woff +0 -0
  32. package/__mf/font/inter-greek-500-normal.f41f43db.woff2 +0 -0
  33. package/__mf/font/inter-greek-600-normal.4ec0c1c1.woff +0 -0
  34. package/__mf/font/inter-greek-600-normal.cc532937.woff2 +0 -0
  35. package/__mf/font/inter-greek-700-normal.5ec6c758.woff +0 -0
  36. package/__mf/font/inter-greek-700-normal.97f0eeeb.woff2 +0 -0
  37. package/__mf/font/inter-greek-900-normal.46b66369.woff2 +0 -0
  38. package/__mf/font/inter-greek-900-normal.9ae3a3c5.woff +0 -0
  39. package/__mf/font/inter-greek-ext-300-normal.10247a66.woff2 +0 -0
  40. package/__mf/font/inter-greek-ext-300-normal.4668e5cb.woff +0 -0
  41. package/__mf/font/inter-greek-ext-400-normal.4ce1df5d.woff2 +0 -0
  42. package/__mf/font/inter-greek-ext-400-normal.88ede1ea.woff +0 -0
  43. package/__mf/font/inter-greek-ext-500-normal.7a4aa726.woff +0 -0
  44. package/__mf/font/inter-greek-ext-500-normal.cbd51e2d.woff2 +0 -0
  45. package/__mf/font/inter-greek-ext-600-normal.089a95ee.woff +0 -0
  46. package/__mf/font/inter-greek-ext-600-normal.1f33d317.woff2 +0 -0
  47. package/__mf/font/inter-greek-ext-700-normal.31f1075d.woff +0 -0
  48. package/__mf/font/inter-greek-ext-700-normal.827cd618.woff2 +0 -0
  49. package/__mf/font/inter-greek-ext-900-normal.531bcee7.woff +0 -0
  50. package/__mf/font/inter-greek-ext-900-normal.8a9b36b9.woff2 +0 -0
  51. package/__mf/font/inter-latin-300-normal.15fb600d.woff2 +0 -0
  52. package/__mf/font/inter-latin-300-normal.6f95f590.woff +0 -0
  53. package/__mf/font/inter-latin-400-normal.2c7a775c.woff +0 -0
  54. package/__mf/font/inter-latin-400-normal.ef6d3f52.woff2 +0 -0
  55. package/__mf/font/inter-latin-500-normal.b7b43ace.woff2 +0 -0
  56. package/__mf/font/inter-latin-500-normal.cb4c8ceb.woff +0 -0
  57. package/__mf/font/inter-latin-600-normal.8fb1a964.woff2 +0 -0
  58. package/__mf/font/inter-latin-600-normal.ce0f5f43.woff +0 -0
  59. package/__mf/font/inter-latin-700-normal.953b7aa5.woff2 +0 -0
  60. package/__mf/font/inter-latin-700-normal.9c21d4dc.woff +0 -0
  61. package/__mf/font/inter-latin-900-normal.2a8028ec.woff2 +0 -0
  62. package/__mf/font/inter-latin-900-normal.fa252135.woff +0 -0
  63. package/__mf/font/inter-latin-ext-300-normal.167cc8c9.woff2 +0 -0
  64. package/__mf/font/inter-latin-ext-300-normal.f695be66.woff +0 -0
  65. package/__mf/font/inter-latin-ext-400-normal.32a25442.woff2 +0 -0
  66. package/__mf/font/inter-latin-ext-400-normal.4edcaace.woff +0 -0
  67. package/__mf/font/inter-latin-ext-500-normal.a19a84a6.woff +0 -0
  68. package/__mf/font/inter-latin-ext-500-normal.d9b491de.woff2 +0 -0
  69. package/__mf/font/inter-latin-ext-600-normal.38b075d8.woff2 +0 -0
  70. package/__mf/font/inter-latin-ext-600-normal.49faa47a.woff +0 -0
  71. package/__mf/font/inter-latin-ext-700-normal.93534b50.woff +0 -0
  72. package/__mf/font/inter-latin-ext-700-normal.b63daa1a.woff2 +0 -0
  73. package/__mf/font/inter-latin-ext-900-normal.0efdb307.woff +0 -0
  74. package/__mf/font/inter-latin-ext-900-normal.9c0fc2c7.woff2 +0 -0
  75. package/__mf/font/inter-vietnamese-300-normal.aad496d8.woff +0 -0
  76. package/__mf/font/inter-vietnamese-300-normal.ad9ef503.woff2 +0 -0
  77. package/__mf/font/inter-vietnamese-400-normal.a9dd2faf.woff +0 -0
  78. package/__mf/font/inter-vietnamese-400-normal.de4fc44f.woff2 +0 -0
  79. package/__mf/font/inter-vietnamese-500-normal.7c0a695f.woff2 +0 -0
  80. package/__mf/font/inter-vietnamese-500-normal.a3a73b95.woff +0 -0
  81. package/__mf/font/inter-vietnamese-600-normal.9d518599.woff2 +0 -0
  82. package/__mf/font/inter-vietnamese-600-normal.c5ce3fcb.woff +0 -0
  83. package/__mf/font/inter-vietnamese-700-normal.bc68b199.woff +0 -0
  84. package/__mf/font/inter-vietnamese-700-normal.faf12809.woff2 +0 -0
  85. package/__mf/font/inter-vietnamese-900-normal.2b782045.woff +0 -0
  86. package/__mf/font/inter-vietnamese-900-normal.e639b65a.woff2 +0 -0
  87. package/__mf/js/LogsTable.471dc288.js +7 -0
  88. package/__mf/js/async/1159.9276d668.js +22 -0
  89. package/__mf/js/async/1519.40e06bfc.js +1 -0
  90. package/__mf/js/async/1616.1b9a06fe.js +1 -0
  91. package/__mf/js/async/1805.ab82c1ef.js +1 -0
  92. package/__mf/js/async/20.b04ebcaa.js +3 -0
  93. package/__mf/js/async/2043.956cdbbb.js +2 -0
  94. package/__mf/js/async/256.20a94089.js +1 -0
  95. package/__mf/js/async/2842.4aad5bc1.js +1 -0
  96. package/__mf/js/async/304.8985bacb.js +37 -0
  97. package/__mf/js/async/392.f9cb0cfc.js +2 -0
  98. package/__mf/js/async/4077.e9103d7c.js +1 -0
  99. package/__mf/js/async/4121.c9ef0518.js +2 -0
  100. package/__mf/js/async/4869.940da5d7.js +1 -0
  101. package/__mf/js/async/5002.1fe02654.js +1 -0
  102. package/__mf/js/async/5071.87183f5a.js +1 -0
  103. package/__mf/js/async/5369.0aa8782c.js +7 -0
  104. package/__mf/js/async/{193.39599d76.js.LICENSE.txt → 5369.0aa8782c.js.LICENSE.txt} +19 -1
  105. package/__mf/js/async/540.d4d0de7f.js +2 -0
  106. package/__mf/js/async/540.d4d0de7f.js.LICENSE.txt +1 -0
  107. package/__mf/js/async/5587.c7e5a39c.js +1 -0
  108. package/__mf/js/async/5652.e6029fc8.js +2 -0
  109. package/__mf/js/async/{1117.0a72bc85.js.LICENSE.txt → 5652.e6029fc8.js.LICENSE.txt} +1 -1
  110. package/__mf/js/async/6274.940dee19.js +2 -0
  111. package/__mf/js/async/6458.b2359789.js +1 -0
  112. package/__mf/js/async/7177.44516b97.js +1 -0
  113. package/__mf/js/async/7192.84e9432b.js +1 -0
  114. package/__mf/js/async/7250.78e3cd06.js +1 -0
  115. package/__mf/js/async/7413.581476fb.js +1 -0
  116. package/__mf/js/async/7445.73c38e72.js +110 -0
  117. package/__mf/js/async/{7445.28262ec0.js.LICENSE.txt → 7445.73c38e72.js.LICENSE.txt} +1 -1
  118. package/__mf/js/async/7452.7c6fe277.js +2 -0
  119. package/__mf/js/async/7968.aaf8a8bc.js +1 -0
  120. package/__mf/js/async/7978.35e0aa88.js +1 -0
  121. package/__mf/js/async/8356.355b4afe.js +1 -0
  122. package/__mf/js/async/8470.878f89da.js +2 -0
  123. package/__mf/js/async/8542.e30a008f.js +1 -0
  124. package/__mf/js/async/8608.072381d3.js +1 -0
  125. package/__mf/js/async/873.a4b44e41.js +1 -0
  126. package/__mf/js/async/9235.33a97899.js +1 -0
  127. package/__mf/js/async/9293.77eed9f0.js +2 -0
  128. package/__mf/js/async/941.c74117a1.js +2 -0
  129. package/__mf/js/async/9588.4e751733.js +1 -0
  130. package/__mf/js/async/__federation_expose_LogsTable.b2bc5b29.js +1 -0
  131. package/__mf/js/async/lib-router.47d4d226.js +2 -0
  132. package/__mf/js/main.04ea2a20.js +7 -0
  133. package/lib/LogsTable.d.ts.map +1 -1
  134. package/lib/LogsTable.js +8 -1
  135. package/lib/LogsTable.js.map +1 -1
  136. package/lib/LogsTableExportAction.d.ts +3 -0
  137. package/lib/LogsTableExportAction.d.ts.map +1 -0
  138. package/lib/LogsTableExportAction.js +67 -0
  139. package/lib/LogsTableExportAction.js.map +1 -0
  140. package/lib/cjs/LogsTable.js +8 -1
  141. package/lib/cjs/LogsTableExportAction.js +80 -0
  142. package/lib/cjs/components/LogRow/LogDetailsTable.js +60 -5
  143. package/lib/cjs/components/LogRow/LogRow.js +18 -7
  144. package/lib/cjs/components/VirtualizedLogsList.js +4 -4
  145. package/lib/cjs/utils/ansi.js +60 -0
  146. package/lib/cjs/utils/copyHelpers.js +4 -2
  147. package/lib/components/LogRow/LogDetailsTable.d.ts +2 -1
  148. package/lib/components/LogRow/LogDetailsTable.d.ts.map +1 -1
  149. package/lib/components/LogRow/LogDetailsTable.js +22 -3
  150. package/lib/components/LogRow/LogDetailsTable.js.map +1 -1
  151. package/lib/components/LogRow/LogRow.d.ts +2 -1
  152. package/lib/components/LogRow/LogRow.d.ts.map +1 -1
  153. package/lib/components/LogRow/LogRow.js +20 -9
  154. package/lib/components/LogRow/LogRow.js.map +1 -1
  155. package/lib/components/LogsList.d.ts +1 -1
  156. package/lib/components/LogsList.js.map +1 -1
  157. package/lib/components/VirtualizedLogsList.d.ts +1 -1
  158. package/lib/components/VirtualizedLogsList.d.ts.map +1 -1
  159. package/lib/components/VirtualizedLogsList.js +5 -5
  160. package/lib/components/VirtualizedLogsList.js.map +1 -1
  161. package/lib/components/hooks/useSeverity.d.ts +1 -1
  162. package/lib/components/hooks/useSeverity.js.map +1 -1
  163. package/lib/components/utils.d.ts +1 -1
  164. package/lib/components/utils.js.map +1 -1
  165. package/lib/model.d.ts +2 -1
  166. package/lib/model.d.ts.map +1 -1
  167. package/lib/model.js.map +1 -1
  168. package/lib/utils/ansi.d.ts +3 -0
  169. package/lib/utils/ansi.d.ts.map +1 -0
  170. package/lib/utils/ansi.js +39 -0
  171. package/lib/utils/ansi.js.map +1 -0
  172. package/lib/utils/copyHelpers.d.ts +1 -1
  173. package/lib/utils/copyHelpers.d.ts.map +1 -1
  174. package/lib/utils/copyHelpers.js +4 -2
  175. package/lib/utils/copyHelpers.js.map +1 -1
  176. package/mf-manifest.json +93 -72
  177. package/mf-stats.json +109 -74
  178. package/package.json +9 -5
  179. package/__mf/css/async/3061.d3010b86.css +0 -1
  180. package/__mf/css/async/5442.d3010b86.css +0 -1
  181. package/__mf/css/async/7823.d3010b86.css +0 -1
  182. package/__mf/font/lato-all-300-normal.322bdf14.woff +0 -0
  183. package/__mf/font/lato-all-400-normal.63513b00.woff +0 -0
  184. package/__mf/font/lato-all-700-normal.bb27db94.woff +0 -0
  185. package/__mf/font/lato-all-900-normal.a27049a3.woff +0 -0
  186. package/__mf/font/lato-latin-300-normal.c5195215.woff2 +0 -0
  187. package/__mf/font/lato-latin-400-normal.b7ffde23.woff2 +0 -0
  188. package/__mf/font/lato-latin-700-normal.d5eb20bc.woff2 +0 -0
  189. package/__mf/font/lato-latin-900-normal.d884a71c.woff2 +0 -0
  190. package/__mf/font/lato-latin-ext-300-normal.abcc64a9.woff2 +0 -0
  191. package/__mf/font/lato-latin-ext-400-normal.6ebed106.woff2 +0 -0
  192. package/__mf/font/lato-latin-ext-700-normal.8697d1d5.woff2 +0 -0
  193. package/__mf/font/lato-latin-ext-900-normal.20a2b415.woff2 +0 -0
  194. package/__mf/js/LogsTable.198d1d4a.js +0 -6
  195. package/__mf/js/async/1117.0a72bc85.js +0 -2
  196. package/__mf/js/async/1240.1a0b69fc.js +0 -1
  197. package/__mf/js/async/1616.832c6e3d.js +0 -1
  198. package/__mf/js/async/1634.90d6ae2a.js +0 -3
  199. package/__mf/js/async/193.39599d76.js +0 -7
  200. package/__mf/js/async/2043.3343388c.js +0 -2
  201. package/__mf/js/async/304.d0edd380.js +0 -37
  202. package/__mf/js/async/392.2e457deb.js +0 -2
  203. package/__mf/js/async/3982.ab5d25af.js +0 -1
  204. package/__mf/js/async/4077.4c4e9533.js +0 -1
  205. package/__mf/js/async/4121.6fa52018.js +0 -2
  206. package/__mf/js/async/5002.c1c54a52.js +0 -1
  207. package/__mf/js/async/5019.84406c37.js +0 -1
  208. package/__mf/js/async/5071.a0b2c6c3.js +0 -1
  209. package/__mf/js/async/5587.180213b1.js +0 -1
  210. package/__mf/js/async/6034.7c4a93c7.js +0 -22
  211. package/__mf/js/async/6274.145959f1.js +0 -2
  212. package/__mf/js/async/6458.4d73f1df.js +0 -1
  213. package/__mf/js/async/7177.848ebbb2.js +0 -1
  214. package/__mf/js/async/7192.269aa1db.js +0 -1
  215. package/__mf/js/async/7445.28262ec0.js +0 -110
  216. package/__mf/js/async/7452.60dd8e7a.js +0 -2
  217. package/__mf/js/async/7968.2c2a16b3.js +0 -1
  218. package/__mf/js/async/7978.8fed4f5a.js +0 -1
  219. package/__mf/js/async/8356.9ea56838.js +0 -1
  220. package/__mf/js/async/8470.6f543f7d.js +0 -2
  221. package/__mf/js/async/8542.1802a06b.js +0 -1
  222. package/__mf/js/async/8608.4e8b55b4.js +0 -1
  223. package/__mf/js/async/873.6dbef0bc.js +0 -1
  224. package/__mf/js/async/8859.f8f648fc.js +0 -1
  225. package/__mf/js/async/9235.3d5006e1.js +0 -1
  226. package/__mf/js/async/9293.7e278959.js +0 -2
  227. package/__mf/js/async/941.66a54646.js +0 -2
  228. package/__mf/js/async/9588.1ab96620.js +0 -1
  229. package/__mf/js/async/__federation_expose_LogsTable.018ab634.js +0 -1
  230. package/__mf/js/async/lib-router.04411383.js +0 -2
  231. package/__mf/js/main.363b5188.js +0 -6
  232. /package/__mf/js/async/{6034.7c4a93c7.js.LICENSE.txt → 1159.9276d668.js.LICENSE.txt} +0 -0
  233. /package/__mf/js/async/{2043.3343388c.js.LICENSE.txt → 2043.956cdbbb.js.LICENSE.txt} +0 -0
  234. /package/__mf/js/async/{392.2e457deb.js.LICENSE.txt → 392.f9cb0cfc.js.LICENSE.txt} +0 -0
  235. /package/__mf/js/async/{4121.6fa52018.js.LICENSE.txt → 4121.c9ef0518.js.LICENSE.txt} +0 -0
  236. /package/__mf/js/async/{6274.145959f1.js.LICENSE.txt → 6274.940dee19.js.LICENSE.txt} +0 -0
  237. /package/__mf/js/async/{7452.60dd8e7a.js.LICENSE.txt → 7452.7c6fe277.js.LICENSE.txt} +0 -0
  238. /package/__mf/js/async/{8470.6f543f7d.js.LICENSE.txt → 8470.878f89da.js.LICENSE.txt} +0 -0
  239. /package/__mf/js/async/{941.66a54646.js.LICENSE.txt → 941.c74117a1.js.LICENSE.txt} +0 -0
  240. /package/__mf/js/async/{lib-router.04411383.js.LICENSE.txt → lib-router.47d4d226.js.LICENSE.txt} +0 -0
@@ -21,13 +21,66 @@ Object.defineProperty(exports, "LogDetailsTable", {
21
21
  }
22
22
  });
23
23
  const _jsxruntime = require("react/jsx-runtime");
24
- const _react = /*#__PURE__*/ _interop_require_default(require("react"));
24
+ const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
25
25
  const _material = require("@mui/material");
26
- function _interop_require_default(obj) {
27
- return obj && obj.__esModule ? obj : {
28
- default: obj
26
+ require("./ansiColors.css");
27
+ const _ansi = require("../../utils/ansi");
28
+ function _getRequireWildcardCache(nodeInterop) {
29
+ if (typeof WeakMap !== "function") return null;
30
+ var cacheBabelInterop = new WeakMap();
31
+ var cacheNodeInterop = new WeakMap();
32
+ return (_getRequireWildcardCache = function(nodeInterop) {
33
+ return nodeInterop ? cacheNodeInterop : cacheBabelInterop;
34
+ })(nodeInterop);
35
+ }
36
+ function _interop_require_wildcard(obj, nodeInterop) {
37
+ if (!nodeInterop && obj && obj.__esModule) {
38
+ return obj;
39
+ }
40
+ if (obj === null || typeof obj !== "object" && typeof obj !== "function") {
41
+ return {
42
+ default: obj
43
+ };
44
+ }
45
+ var cache = _getRequireWildcardCache(nodeInterop);
46
+ if (cache && cache.has(obj)) {
47
+ return cache.get(obj);
48
+ }
49
+ var newObj = {
50
+ __proto__: null
29
51
  };
52
+ var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor;
53
+ for(var key in obj){
54
+ if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) {
55
+ var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null;
56
+ if (desc && (desc.get || desc.set)) {
57
+ Object.defineProperty(newObj, key, desc);
58
+ } else {
59
+ newObj[key] = obj[key];
60
+ }
61
+ }
62
+ }
63
+ newObj.default = obj;
64
+ if (cache) {
65
+ cache.set(obj, newObj);
66
+ }
67
+ return newObj;
30
68
  }
69
+ const AnsiValue = ({ value })=>{
70
+ const ansiHtml = (0, _react.useMemo)(()=>(0, _ansi.ansiToSanitizedHtml)(value), [
71
+ value
72
+ ]);
73
+ if (ansiHtml) {
74
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)("span", {
75
+ dangerouslySetInnerHTML: {
76
+ __html: ansiHtml
77
+ }
78
+ });
79
+ }
80
+ return /*#__PURE__*/ (0, _jsxruntime.jsx)(_jsxruntime.Fragment, {
81
+ children: value
82
+ });
83
+ };
31
84
  const LogDetailsTable = ({ log })=>{
32
85
  const theme = (0, _material.useTheme)();
33
86
  return /*#__PURE__*/ (0, _jsxruntime.jsx)(_material.Table, {
@@ -62,7 +115,9 @@ const LogDetailsTable = ({ log })=>{
62
115
  wordBreak: 'break-word',
63
116
  width: '67%'
64
117
  },
65
- children: value !== undefined && value !== null && value !== '' ? value : '--'
118
+ children: value !== undefined && value !== null && value !== '' ? /*#__PURE__*/ (0, _jsxruntime.jsx)(AnsiValue, {
119
+ value: value
120
+ }) : '--'
66
121
  })
67
122
  ]
68
123
  }, key))
@@ -21,19 +21,21 @@ Object.defineProperty(exports, "LogRow", {
21
21
  }
22
22
  });
23
23
  const _jsxruntime = require("react/jsx-runtime");
24
- const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
25
24
  const _material = require("@mui/material");
25
+ const _Check = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Check"));
26
+ const _ChevronDown = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ChevronDown"));
26
27
  const _ChevronRight = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ChevronRight"));
28
+ const _CodeJson = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/CodeJson"));
27
29
  const _ContentCopy = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ContentCopy"));
28
- const _ChevronDown = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/ChevronDown"));
29
30
  const _FormatQuoteClose = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/FormatQuoteClose"));
30
- const _CodeJson = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/CodeJson"));
31
- const _Check = /*#__PURE__*/ _interop_require_default(require("mdi-material-ui/Check"));
32
- const _useSeverity = require("../hooks/useSeverity");
31
+ const _react = /*#__PURE__*/ _interop_require_wildcard(require("react"));
32
+ const _ansi = require("../../utils/ansi");
33
33
  const _copyHelpers = require("../../utils/copyHelpers");
34
+ const _useSeverity = require("../hooks/useSeverity");
35
+ const _LogDetailsTable = require("./LogDetailsTable");
34
36
  const _LogTimestamp = require("./LogTimestamp");
35
37
  const _LogsStyles = require("./LogsStyles");
36
- const _LogDetailsTable = require("./LogDetailsTable");
38
+ require("./ansiColors.css");
37
39
  function _interop_require_default(obj) {
38
40
  return obj && obj.__esModule ? obj : {
39
41
  default: obj
@@ -84,6 +86,9 @@ const COPY_SUCCESS_DURATION_MS = 1500;
84
86
  const DefaultLogRow = ({ log, isExpanded, index, onToggle, isExpandable = true, showTime = false, allowWrap = false, isSelected = false, onSelect, itemActionButtons })=>{
85
87
  const theme = (0, _material.useTheme)();
86
88
  const severityColor = (0, _useSeverity.useSeverityColor)(log);
89
+ const ansiHtml = (0, _react.useMemo)(()=>log ? (0, _ansi.ansiToSanitizedHtml)(log.line) : null, [
90
+ log
91
+ ]);
87
92
  const [isHovered, setIsHovered] = (0, _react.useState)(false);
88
93
  const [anchorEl, setAnchorEl] = (0, _react.useState)(null);
89
94
  const [copySuccess, setCopySuccess] = (0, _react.useState)(false);
@@ -203,7 +208,13 @@ const DefaultLogRow = ({ log, isExpanded, index, onToggle, isExpandable = true,
203
208
  alignItems: 'center'
204
209
  },
205
210
  children: [
206
- /*#__PURE__*/ (0, _jsxruntime.jsx)(_LogsStyles.LogText, {
211
+ ansiHtml ? /*#__PURE__*/ (0, _jsxruntime.jsx)(_LogsStyles.LogText, {
212
+ variant: "body2",
213
+ allowWrap: allowWrap,
214
+ dangerouslySetInnerHTML: {
215
+ __html: ansiHtml
216
+ }
217
+ }) : /*#__PURE__*/ (0, _jsxruntime.jsx)(_LogsStyles.LogText, {
207
218
  variant: "body2",
208
219
  allowWrap: allowWrap,
209
220
  children: log.line
@@ -78,8 +78,8 @@ function _interop_require_wildcard(obj, nodeInterop) {
78
78
  }
79
79
  const PERSES_LOGSTABLE_HINTS_DISMISSED = 'PERSES_LOGSTABLE_HINTS_DISMISSED';
80
80
  const COPY_TOAST_DURATION_MS = 5000;
81
- // Detect Mac for keyboard shortcuts display
82
- const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.userAgent);
81
+ // Platform-aware modifier key display using TanStack's formatForDisplay
82
+ const modKeyDisplay = (0, _dashboards.formatForDisplay)('Mod');
83
83
  const VirtualizedLogsList = ({ logs, spec, expandedRows, onToggleExpand })=>{
84
84
  const theme = (0, _material.useTheme)();
85
85
  const [selectedRows, setSelectedRows] = (0, _react.useState)(new Set());
@@ -351,7 +351,7 @@ const VirtualizedLogsList = ({ logs, spec, expandedRows, onToggleExpand })=>{
351
351
  opacity: 0.8
352
352
  },
353
353
  children: [
354
- isMac ? '⌘' : 'Ctrl',
354
+ modKeyDisplay,
355
355
  "+Click to select"
356
356
  ]
357
357
  }),
@@ -382,7 +382,7 @@ const VirtualizedLogsList = ({ logs, spec, expandedRows, onToggleExpand })=>{
382
382
  opacity: 0.8
383
383
  },
384
384
  children: [
385
- isMac ? '⌘' : 'Ctrl',
385
+ modKeyDisplay,
386
386
  "+C to copy"
387
387
  ]
388
388
  }),
@@ -0,0 +1,60 @@
1
+ // Copyright The Perses Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ "use strict";
14
+ Object.defineProperty(exports, "__esModule", {
15
+ value: true
16
+ });
17
+ function _export(target, all) {
18
+ for(var name in all)Object.defineProperty(target, name, {
19
+ enumerable: true,
20
+ get: Object.getOwnPropertyDescriptor(all, name).get
21
+ });
22
+ }
23
+ _export(exports, {
24
+ get ansiToSanitizedHtml () {
25
+ return ansiToSanitizedHtml;
26
+ },
27
+ get stripAnsi () {
28
+ return stripAnsi;
29
+ }
30
+ });
31
+ const _ansi_up = require("ansi_up");
32
+ const _dompurify = /*#__PURE__*/ _interop_require_default(require("dompurify"));
33
+ function _interop_require_default(obj) {
34
+ return obj && obj.__esModule ? obj : {
35
+ default: obj
36
+ };
37
+ }
38
+ const ansiUp = new _ansi_up.AnsiUp();
39
+ ansiUp.use_classes = true;
40
+ const ESC = String.fromCharCode(27);
41
+ const ANSI_REGEX = new RegExp(ESC + '\\[[0-9;]*m');
42
+ function ansiToSanitizedHtml(text) {
43
+ if (!ANSI_REGEX.test(text)) {
44
+ return null;
45
+ }
46
+ const html = ansiUp.ansi_to_html(text);
47
+ return _dompurify.default.sanitize(html, {
48
+ ALLOWED_TAGS: [
49
+ 'span'
50
+ ],
51
+ ALLOWED_ATTR: [
52
+ 'class',
53
+ 'style'
54
+ ]
55
+ });
56
+ }
57
+ const ANSI_STRIP_REGEX = new RegExp(ESC + '\\[[0-9;]*m', 'g');
58
+ function stripAnsi(text) {
59
+ return text.replace(ANSI_STRIP_REGEX, '');
60
+ }
@@ -40,6 +40,7 @@ _export(exports, {
40
40
  return formatTimestamp;
41
41
  }
42
42
  });
43
+ const _ansi = require("./ansi");
43
44
  function formatTimestamp(timestamp) {
44
45
  const date = typeof timestamp === 'number' ? new Date(timestamp * 1000) : parseTimestamp(timestamp);
45
46
  return date.toISOString();
@@ -57,10 +58,11 @@ function formatLabels(labels) {
57
58
  function formatLogEntry(log) {
58
59
  const timestamp = formatTimestamp(log.timestamp);
59
60
  const labels = formatLabels(log.labels || {});
60
- return labels ? `${timestamp} ${labels} ${log.line}` : `${timestamp} ${log.line}`;
61
+ const cleanLine = (0, _ansi.stripAnsi)(log.line);
62
+ return labels ? `${timestamp} ${labels} ${cleanLine}` : `${timestamp} ${cleanLine}`;
61
63
  }
62
64
  function formatLogMessage(log) {
63
- return log.line;
65
+ return (0, _ansi.stripAnsi)(log.line);
64
66
  }
65
67
  function formatLogAsJson(log) {
66
68
  return JSON.stringify(log, null, 2);
@@ -1,5 +1,6 @@
1
1
  import React from 'react';
2
- import { Labels } from '@perses-dev/core';
2
+ import './ansiColors.css';
3
+ import { Labels } from '@perses-dev/spec';
3
4
  interface LogDetailsTableProps {
4
5
  log: Labels;
5
6
  }
@@ -1 +1 @@
1
- {"version":3,"file":"LogDetailsTable.d.ts","sourceRoot":"","sources":["../../../../src/components/LogRow/LogDetailsTable.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAE1C,UAAU,oBAAoB;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgD1D,CAAC"}
1
+ {"version":3,"file":"LogDetailsTable.d.ts","sourceRoot":"","sources":["../../../../src/components/LogRow/LogDetailsTable.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAkB,MAAM,OAAO,CAAC;AAEvC,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAW1C,UAAU,oBAAoB;IAC5B,GAAG,EAAE,MAAM,CAAC;CACb;AAED,eAAO,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAgD1D,CAAC"}
@@ -1,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  // Copyright The Perses Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -11,8 +11,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import React from 'react';
14
+ import React, { useMemo } from 'react';
15
15
  import { Table, TableBody, TableRow, TableCell, useTheme, alpha } from '@mui/material';
16
+ import './ansiColors.css';
17
+ import { ansiToSanitizedHtml } from '../../utils/ansi';
18
+ const AnsiValue = ({ value })=>{
19
+ const ansiHtml = useMemo(()=>ansiToSanitizedHtml(value), [
20
+ value
21
+ ]);
22
+ if (ansiHtml) {
23
+ return /*#__PURE__*/ _jsx("span", {
24
+ dangerouslySetInnerHTML: {
25
+ __html: ansiHtml
26
+ }
27
+ });
28
+ }
29
+ return /*#__PURE__*/ _jsx(_Fragment, {
30
+ children: value
31
+ });
32
+ };
16
33
  export const LogDetailsTable = ({ log })=>{
17
34
  const theme = useTheme();
18
35
  return /*#__PURE__*/ _jsx(Table, {
@@ -47,7 +64,9 @@ export const LogDetailsTable = ({ log })=>{
47
64
  wordBreak: 'break-word',
48
65
  width: '67%'
49
66
  },
50
- children: value !== undefined && value !== null && value !== '' ? value : '--'
67
+ children: value !== undefined && value !== null && value !== '' ? /*#__PURE__*/ _jsx(AnsiValue, {
68
+ value: value
69
+ }) : '--'
51
70
  })
52
71
  ]
53
72
  }, key))
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/LogRow/LogDetailsTable.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 React from 'react';\nimport { Table, TableBody, TableRow, TableCell, useTheme, alpha } from '@mui/material';\nimport { Labels } from '@perses-dev/core';\n\ninterface LogDetailsTableProps {\n log: Labels;\n}\n\nexport const LogDetailsTable: React.FC<LogDetailsTableProps> = ({ log }) => {\n const theme = useTheme();\n\n return (\n <Table\n size=\"small\"\n sx={{\n border: `1px solid ${theme.palette.divider}`,\n '& .MuiTableCell-root': {\n border: 'none',\n padding: '6px 8px',\n fontSize: '12px',\n },\n }}\n >\n <TableBody>\n {Object.entries(log).map(([key, value]) => (\n <TableRow\n key={key}\n sx={{\n '&:hover': {\n backgroundColor: alpha(theme.palette.action.hover, 0.04),\n },\n }}\n >\n <TableCell\n sx={{\n color: theme.palette.text.secondary,\n fontWeight: 500,\n width: '33%',\n }}\n >\n {key}\n </TableCell>\n <TableCell\n sx={{\n color: theme.palette.text.primary,\n wordBreak: 'break-word',\n width: '67%',\n }}\n >\n {value !== undefined && value !== null && value !== '' ? value : '--'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n );\n};\n"],"names":["React","Table","TableBody","TableRow","TableCell","useTheme","alpha","LogDetailsTable","log","theme","size","sx","border","palette","divider","padding","fontSize","Object","entries","map","key","value","backgroundColor","action","hover","color","text","secondary","fontWeight","width","primary","wordBreak","undefined"],"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,OAAOA,WAAW,QAAQ;AAC1B,SAASC,KAAK,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,KAAK,QAAQ,gBAAgB;AAOvF,OAAO,MAAMC,kBAAkD,CAAC,EAAEC,GAAG,EAAE;IACrE,MAAMC,QAAQJ;IAEd,qBACE,KAACJ;QACCS,MAAK;QACLC,IAAI;YACFC,QAAQ,CAAC,UAAU,EAAEH,MAAMI,OAAO,CAACC,OAAO,EAAE;YAC5C,wBAAwB;gBACtBF,QAAQ;gBACRG,SAAS;gBACTC,UAAU;YACZ;QACF;kBAEA,cAAA,KAACd;sBACEe,OAAOC,OAAO,CAACV,KAAKW,GAAG,CAAC,CAAC,CAACC,KAAKC,MAAM,iBACpC,MAAClB;oBAECQ,IAAI;wBACF,WAAW;4BACTW,iBAAiBhB,MAAMG,MAAMI,OAAO,CAACU,MAAM,CAACC,KAAK,EAAE;wBACrD;oBACF;;sCAEA,KAACpB;4BACCO,IAAI;gCACFc,OAAOhB,MAAMI,OAAO,CAACa,IAAI,CAACC,SAAS;gCACnCC,YAAY;gCACZC,OAAO;4BACT;sCAECT;;sCAEH,KAAChB;4BACCO,IAAI;gCACFc,OAAOhB,MAAMI,OAAO,CAACa,IAAI,CAACI,OAAO;gCACjCC,WAAW;gCACXF,OAAO;4BACT;sCAECR,UAAUW,aAAaX,UAAU,QAAQA,UAAU,KAAKA,QAAQ;;;mBAvB9DD;;;AA8BjB,EAAE"}
1
+ {"version":3,"sources":["../../../../src/components/LogRow/LogDetailsTable.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 React, { useMemo } from 'react';\nimport { Table, TableBody, TableRow, TableCell, useTheme, alpha } from '@mui/material';\nimport './ansiColors.css';\nimport { Labels } from '@perses-dev/spec';\nimport { ansiToSanitizedHtml } from '../../utils/ansi';\n\nconst AnsiValue: React.FC<{ value: string }> = ({ value }) => {\n const ansiHtml = useMemo(() => ansiToSanitizedHtml(value), [value]);\n if (ansiHtml) {\n return <span dangerouslySetInnerHTML={{ __html: ansiHtml }} />;\n }\n return <>{value}</>;\n};\n\ninterface LogDetailsTableProps {\n log: Labels;\n}\n\nexport const LogDetailsTable: React.FC<LogDetailsTableProps> = ({ log }) => {\n const theme = useTheme();\n\n return (\n <Table\n size=\"small\"\n sx={{\n border: `1px solid ${theme.palette.divider}`,\n '& .MuiTableCell-root': {\n border: 'none',\n padding: '6px 8px',\n fontSize: '12px',\n },\n }}\n >\n <TableBody>\n {Object.entries(log).map(([key, value]) => (\n <TableRow\n key={key}\n sx={{\n '&:hover': {\n backgroundColor: alpha(theme.palette.action.hover, 0.04),\n },\n }}\n >\n <TableCell\n sx={{\n color: theme.palette.text.secondary,\n fontWeight: 500,\n width: '33%',\n }}\n >\n {key}\n </TableCell>\n <TableCell\n sx={{\n color: theme.palette.text.primary,\n wordBreak: 'break-word',\n width: '67%',\n }}\n >\n {value !== undefined && value !== null && value !== '' ? <AnsiValue value={value} /> : '--'}\n </TableCell>\n </TableRow>\n ))}\n </TableBody>\n </Table>\n );\n};\n"],"names":["React","useMemo","Table","TableBody","TableRow","TableCell","useTheme","alpha","ansiToSanitizedHtml","AnsiValue","value","ansiHtml","span","dangerouslySetInnerHTML","__html","LogDetailsTable","log","theme","size","sx","border","palette","divider","padding","fontSize","Object","entries","map","key","backgroundColor","action","hover","color","text","secondary","fontWeight","width","primary","wordBreak","undefined"],"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,OAAOA,SAASC,OAAO,QAAQ,QAAQ;AACvC,SAASC,KAAK,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,SAAS,EAAEC,QAAQ,EAAEC,KAAK,QAAQ,gBAAgB;AACvF,OAAO,mBAAmB;AAE1B,SAASC,mBAAmB,QAAQ,mBAAmB;AAEvD,MAAMC,YAAyC,CAAC,EAAEC,KAAK,EAAE;IACvD,MAAMC,WAAWV,QAAQ,IAAMO,oBAAoBE,QAAQ;QAACA;KAAM;IAClE,IAAIC,UAAU;QACZ,qBAAO,KAACC;YAAKC,yBAAyB;gBAAEC,QAAQH;YAAS;;IAC3D;IACA,qBAAO;kBAAGD;;AACZ;AAMA,OAAO,MAAMK,kBAAkD,CAAC,EAAEC,GAAG,EAAE;IACrE,MAAMC,QAAQX;IAEd,qBACE,KAACJ;QACCgB,MAAK;QACLC,IAAI;YACFC,QAAQ,CAAC,UAAU,EAAEH,MAAMI,OAAO,CAACC,OAAO,EAAE;YAC5C,wBAAwB;gBACtBF,QAAQ;gBACRG,SAAS;gBACTC,UAAU;YACZ;QACF;kBAEA,cAAA,KAACrB;sBACEsB,OAAOC,OAAO,CAACV,KAAKW,GAAG,CAAC,CAAC,CAACC,KAAKlB,MAAM,iBACpC,MAACN;oBAECe,IAAI;wBACF,WAAW;4BACTU,iBAAiBtB,MAAMU,MAAMI,OAAO,CAACS,MAAM,CAACC,KAAK,EAAE;wBACrD;oBACF;;sCAEA,KAAC1B;4BACCc,IAAI;gCACFa,OAAOf,MAAMI,OAAO,CAACY,IAAI,CAACC,SAAS;gCACnCC,YAAY;gCACZC,OAAO;4BACT;sCAECR;;sCAEH,KAACvB;4BACCc,IAAI;gCACFa,OAAOf,MAAMI,OAAO,CAACY,IAAI,CAACI,OAAO;gCACjCC,WAAW;gCACXF,OAAO;4BACT;sCAEC1B,UAAU6B,aAAa7B,UAAU,QAAQA,UAAU,mBAAK,KAACD;gCAAUC,OAAOA;iCAAY;;;mBAvBpFkB;;;AA8BjB,EAAE"}
@@ -1,5 +1,6 @@
1
1
  import React, { ReactNode } from 'react';
2
- import { LogEntry } from '@perses-dev/core';
2
+ import { LogEntry } from '@perses-dev/spec';
3
+ import './ansiColors.css';
3
4
  interface LogRowProps {
4
5
  log?: LogEntry;
5
6
  index: number;
@@ -1 +1 @@
1
- {"version":3,"file":"LogRow.d.ts","sourceRoot":"","sources":["../../../../src/components/LogRow/LogRow.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,EAAkD,SAAS,EAAE,MAAM,OAAO,CAAC;AAkBzF,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAS5C,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC5D,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC;CACjC;AAqTD,eAAO,MAAM,MAAM,yCAAsB,CAAC"}
1
+ {"version":3,"file":"LogRow.d.ts","sourceRoot":"","sources":["../../../../src/components/LogRow/LogRow.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,EAAQ,SAAS,EAAqD,MAAM,OAAO,CAAC;AAClG,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAO5C,OAAO,kBAAkB,CAAC;AAI1B,UAAU,WAAW;IACnB,GAAG,CAAC,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC5D,iBAAiB,CAAC,EAAE,SAAS,EAAE,CAAC;CACjC;AA0TD,eAAO,MAAM,MAAM,yCAAsB,CAAC"}
@@ -11,23 +11,28 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import React, { memo, useCallback, useState, useRef, useEffect } from 'react';
15
- import { Box, Collapse, useTheme, IconButton, Tooltip, Menu, MenuItem, ListItemIcon, ListItemText } from '@mui/material';
14
+ import { Box, Collapse, IconButton, ListItemIcon, ListItemText, Menu, MenuItem, Tooltip, useTheme } from '@mui/material';
15
+ import Check from 'mdi-material-ui/Check';
16
+ import ChevronDown from 'mdi-material-ui/ChevronDown';
16
17
  import ChevronRight from 'mdi-material-ui/ChevronRight';
18
+ import CodeJson from 'mdi-material-ui/CodeJson';
17
19
  import ContentCopy from 'mdi-material-ui/ContentCopy';
18
- import ChevronDown from 'mdi-material-ui/ChevronDown';
19
20
  import FormatQuoteClose from 'mdi-material-ui/FormatQuoteClose';
20
- import CodeJson from 'mdi-material-ui/CodeJson';
21
- import Check from 'mdi-material-ui/Check';
21
+ import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
22
+ import { ansiToSanitizedHtml } from '../../utils/ansi';
23
+ import { formatLogAsJson, formatLogEntry, formatLogMessage } from '../../utils/copyHelpers';
22
24
  import { useSeverityColor } from '../hooks/useSeverity';
23
- import { formatLogEntry, formatLogMessage, formatLogAsJson } from '../../utils/copyHelpers';
24
- import { LogTimestamp } from './LogTimestamp';
25
- import { LogRowContainer, LogRowContent, ExpandButton, LogText } from './LogsStyles';
26
25
  import { LogDetailsTable } from './LogDetailsTable';
26
+ import { LogTimestamp } from './LogTimestamp';
27
+ import { ExpandButton, LogRowContainer, LogRowContent, LogText } from './LogsStyles';
28
+ import './ansiColors.css';
27
29
  const COPY_SUCCESS_DURATION_MS = 1500;
28
30
  const DefaultLogRow = ({ log, isExpanded, index, onToggle, isExpandable = true, showTime = false, allowWrap = false, isSelected = false, onSelect, itemActionButtons })=>{
29
31
  const theme = useTheme();
30
32
  const severityColor = useSeverityColor(log);
33
+ const ansiHtml = useMemo(()=>log ? ansiToSanitizedHtml(log.line) : null, [
34
+ log
35
+ ]);
31
36
  const [isHovered, setIsHovered] = useState(false);
32
37
  const [anchorEl, setAnchorEl] = useState(null);
33
38
  const [copySuccess, setCopySuccess] = useState(false);
@@ -147,7 +152,13 @@ const DefaultLogRow = ({ log, isExpanded, index, onToggle, isExpandable = true,
147
152
  alignItems: 'center'
148
153
  },
149
154
  children: [
150
- /*#__PURE__*/ _jsx(LogText, {
155
+ ansiHtml ? /*#__PURE__*/ _jsx(LogText, {
156
+ variant: "body2",
157
+ allowWrap: allowWrap,
158
+ dangerouslySetInnerHTML: {
159
+ __html: ansiHtml
160
+ }
161
+ }) : /*#__PURE__*/ _jsx(LogText, {
151
162
  variant: "body2",
152
163
  allowWrap: allowWrap,
153
164
  children: log.line
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/components/LogRow/LogRow.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 React, { memo, useCallback, useState, useRef, useEffect, ReactNode } from 'react';\nimport {\n Box,\n Collapse,\n useTheme,\n IconButton,\n Tooltip,\n Menu,\n MenuItem,\n ListItemIcon,\n ListItemText,\n} from '@mui/material';\nimport ChevronRight from 'mdi-material-ui/ChevronRight';\nimport ContentCopy from 'mdi-material-ui/ContentCopy';\nimport ChevronDown from 'mdi-material-ui/ChevronDown';\nimport FormatQuoteClose from 'mdi-material-ui/FormatQuoteClose';\nimport CodeJson from 'mdi-material-ui/CodeJson';\nimport Check from 'mdi-material-ui/Check';\nimport { LogEntry } from '@perses-dev/core';\nimport { useSeverityColor } from '../hooks/useSeverity';\nimport { formatLogEntry, formatLogMessage, formatLogAsJson } from '../../utils/copyHelpers';\nimport { LogTimestamp } from './LogTimestamp';\nimport { LogRowContainer, LogRowContent, ExpandButton, LogText } from './LogsStyles';\nimport { LogDetailsTable } from './LogDetailsTable';\n\nconst COPY_SUCCESS_DURATION_MS = 1500;\n\ninterface LogRowProps {\n log?: LogEntry;\n index: number;\n isExpanded: boolean;\n onToggle: (index: number) => void;\n isExpandable?: boolean;\n showTime?: boolean;\n allowWrap?: boolean;\n isSelected?: boolean;\n onSelect?: (index: number, event: React.MouseEvent) => void;\n itemActionButtons?: ReactNode[];\n}\n\nconst DefaultLogRow: React.FC<LogRowProps> = ({\n log,\n isExpanded,\n index,\n onToggle,\n isExpandable = true,\n showTime = false,\n allowWrap = false,\n isSelected = false,\n onSelect,\n itemActionButtons,\n}) => {\n const theme = useTheme();\n const severityColor = useSeverityColor(log);\n const [isHovered, setIsHovered] = useState(false);\n const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n const [copySuccess, setCopySuccess] = useState(false);\n const rowRef = useRef<HTMLDivElement>(null);\n const copyTimeoutRef = useRef<number | null>(null);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return (): void => {\n if (copyTimeoutRef.current) {\n window.clearTimeout(copyTimeoutRef.current);\n }\n };\n }, []);\n\n const handleToggle = useCallback(\n (e: React.MouseEvent) => {\n if (isExpandable) {\n e.stopPropagation();\n onToggle(index);\n }\n },\n [isExpandable, onToggle, index]\n );\n\n const handleRowMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (onSelect) {\n onSelect(index, e);\n }\n },\n [onSelect, index]\n );\n\n const handleOpenMenu = useCallback((e: React.MouseEvent<HTMLElement>) => {\n e.stopPropagation();\n setAnchorEl(e.currentTarget);\n }, []);\n\n const handleCloseMenu = useCallback(() => {\n setAnchorEl(null);\n setIsHovered(false);\n }, []);\n\n const handleCopy = useCallback(\n async (format: 'full' | 'message' | 'json') => {\n if (!log) return;\n\n let text: string;\n switch (format) {\n case 'message':\n text = formatLogMessage(log);\n break;\n case 'json':\n text = formatLogAsJson(log);\n break;\n case 'full':\n default:\n text = formatLogEntry(log);\n }\n\n await navigator.clipboard.writeText(text);\n setCopySuccess(true);\n handleCloseMenu();\n\n // Clear existing timeout\n if (copyTimeoutRef.current) {\n window.clearTimeout(copyTimeoutRef.current);\n }\n\n // Reset success state after configured duration\n copyTimeoutRef.current = window.setTimeout(() => {\n setCopySuccess(false);\n }, COPY_SUCCESS_DURATION_MS);\n },\n [log, handleCloseMenu]\n );\n\n if (!log) return null;\n\n const hasRowActions = itemActionButtons && itemActionButtons.length > 0;\n\n return (\n <LogRowContainer\n severityColor={severityColor}\n ref={rowRef}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => {\n if (!anchorEl) {\n setIsHovered(false);\n }\n }}\n data-log-index={index}\n data-testid={`log-row-container-${index}`}\n >\n <LogRowContent\n onMouseDown={handleRowMouseDown}\n isExpandable={isExpandable}\n isHighlighted={Boolean(anchorEl)}\n hasRowActions={hasRowActions}\n isSelected={isSelected}\n >\n {isExpandable && (\n <Box\n onClick={handleToggle}\n sx={{\n display: 'flex',\n alignItems: 'center',\n width: '16px',\n justifyContent: 'center',\n cursor: 'pointer',\n }}\n >\n <ExpandButton size=\"small\" isExpanded={isExpanded}>\n <ChevronRight sx={{ fontSize: '12px' }} />\n </ExpandButton>\n </Box>\n )}\n\n <LogTimestamp timestamp={log.timestamp} />\n\n <Box\n sx={{\n display: 'flex',\n gap: '10px',\n marginLeft: '36px',\n alignItems: 'center',\n }}\n >\n <LogText variant=\"body2\" allowWrap={allowWrap}>\n {log.line}\n </LogText>\n <Tooltip title={copySuccess ? 'Copied!' : 'Copy options'}>\n <IconButton\n size=\"small\"\n onClick={handleOpenMenu}\n aria-label=\"Copy log options\"\n sx={{\n padding: '4px',\n marginLeft: 'auto',\n color: copySuccess ? theme.palette.success.main : theme.palette.text.secondary,\n opacity: isHovered || Boolean(anchorEl) || copySuccess ? 1 : 0,\n pointerEvents: isHovered || Boolean(anchorEl) || copySuccess ? 'auto' : 'none',\n transition: 'opacity 0.08s ease, color 0.2s ease',\n '&:hover': {\n color: copySuccess ? theme.palette.success.main : theme.palette.primary.main,\n backgroundColor: theme.palette.action.hover,\n },\n borderRadius: '4px',\n display: 'flex',\n gap: '2px',\n }}\n >\n {copySuccess ? (\n <Check sx={{ fontSize: '14px' }} />\n ) : (\n <>\n <ContentCopy sx={{ fontSize: '14px' }} />\n <ChevronDown sx={{ fontSize: '12px' }} />\n </>\n )}\n </IconButton>\n </Tooltip>\n {hasRowActions && (\n <Box\n sx={{\n display: 'flex',\n gap: '4px',\n alignItems: 'center',\n opacity: isHovered || Boolean(anchorEl) ? 1 : 0,\n pointerEvents: isHovered || Boolean(anchorEl) ? 'auto' : 'none',\n transition: 'opacity 0.08s ease',\n }}\n >\n {itemActionButtons}\n </Box>\n )}\n <Menu\n anchorEl={anchorEl}\n open={Boolean(anchorEl)}\n onClose={handleCloseMenu}\n onClick={(e) => e.stopPropagation()}\n aria-label=\"Copy format options\"\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'right',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'right',\n }}\n slotProps={{\n paper: {\n sx: {\n mt: 0.5,\n minWidth: 180,\n boxShadow: theme.shadows[3],\n },\n },\n }}\n >\n <MenuItem\n onClick={() => handleCopy('full')}\n sx={{\n py: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n <ListItemIcon>\n <ContentCopy fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n primary=\"Copy log\"\n secondary=\"Timestamp + labels + message\"\n slotProps={{\n primary: { fontSize: '14px' },\n secondary: { fontSize: '11px' },\n }}\n />\n </MenuItem>\n <MenuItem\n onClick={() => handleCopy('message')}\n sx={{\n py: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n <ListItemIcon>\n <FormatQuoteClose fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n primary=\"Copy message\"\n secondary=\"Message text only\"\n slotProps={{\n primary: { fontSize: '14px' },\n secondary: { fontSize: '11px' },\n }}\n />\n </MenuItem>\n <MenuItem\n onClick={() => handleCopy('json')}\n sx={{\n py: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n <ListItemIcon>\n <CodeJson fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n primary=\"Copy as JSON\"\n secondary=\"Full log entry\"\n slotProps={{\n primary: { fontSize: '14px' },\n secondary: { fontSize: '11px' },\n }}\n />\n </MenuItem>\n </Menu>\n </Box>\n </LogRowContent>\n\n <Collapse in={isExpanded} timeout={200}>\n <Box sx={{ padding: '8px' }}>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: !showTime ? '1fr' : '8px minmax(160px, max-content) 1fr',\n gap: '12px',\n }}\n >\n {showTime && (\n <>\n <Box />\n <Box />\n </>\n )}\n <Box>\n <LogDetailsTable log={log.labels} />\n </Box>\n </Box>\n </Box>\n </Collapse>\n </LogRowContainer>\n );\n};\n\nexport const LogRow = memo(DefaultLogRow);\nLogRow.displayName = 'LogRow';\n"],"names":["React","memo","useCallback","useState","useRef","useEffect","Box","Collapse","useTheme","IconButton","Tooltip","Menu","MenuItem","ListItemIcon","ListItemText","ChevronRight","ContentCopy","ChevronDown","FormatQuoteClose","CodeJson","Check","useSeverityColor","formatLogEntry","formatLogMessage","formatLogAsJson","LogTimestamp","LogRowContainer","LogRowContent","ExpandButton","LogText","LogDetailsTable","COPY_SUCCESS_DURATION_MS","DefaultLogRow","log","isExpanded","index","onToggle","isExpandable","showTime","allowWrap","isSelected","onSelect","itemActionButtons","theme","severityColor","isHovered","setIsHovered","anchorEl","setAnchorEl","copySuccess","setCopySuccess","rowRef","copyTimeoutRef","current","window","clearTimeout","handleToggle","e","stopPropagation","handleRowMouseDown","handleOpenMenu","currentTarget","handleCloseMenu","handleCopy","format","text","navigator","clipboard","writeText","setTimeout","hasRowActions","length","ref","onMouseEnter","onMouseLeave","data-log-index","data-testid","onMouseDown","isHighlighted","Boolean","onClick","sx","display","alignItems","width","justifyContent","cursor","size","fontSize","timestamp","gap","marginLeft","variant","line","title","aria-label","padding","color","palette","success","main","secondary","opacity","pointerEvents","transition","primary","backgroundColor","action","hover","borderRadius","open","onClose","anchorOrigin","vertical","horizontal","transformOrigin","slotProps","paper","mt","minWidth","boxShadow","shadows","py","in","timeout","gridTemplateColumns","labels","LogRow","displayName"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/components/LogRow/LogRow.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 {\n Box,\n Collapse,\n IconButton,\n ListItemIcon,\n ListItemText,\n Menu,\n MenuItem,\n Tooltip,\n useTheme,\n} from '@mui/material';\nimport Check from 'mdi-material-ui/Check';\nimport ChevronDown from 'mdi-material-ui/ChevronDown';\nimport ChevronRight from 'mdi-material-ui/ChevronRight';\nimport CodeJson from 'mdi-material-ui/CodeJson';\nimport ContentCopy from 'mdi-material-ui/ContentCopy';\nimport FormatQuoteClose from 'mdi-material-ui/FormatQuoteClose';\nimport React, { memo, ReactNode, useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport { LogEntry } from '@perses-dev/spec';\nimport { ansiToSanitizedHtml } from '../../utils/ansi';\nimport { formatLogAsJson, formatLogEntry, formatLogMessage } from '../../utils/copyHelpers';\nimport { useSeverityColor } from '../hooks/useSeverity';\nimport { LogDetailsTable } from './LogDetailsTable';\nimport { LogTimestamp } from './LogTimestamp';\nimport { ExpandButton, LogRowContainer, LogRowContent, LogText } from './LogsStyles';\nimport './ansiColors.css';\n\nconst COPY_SUCCESS_DURATION_MS = 1500;\n\ninterface LogRowProps {\n log?: LogEntry;\n index: number;\n isExpanded: boolean;\n onToggle: (index: number) => void;\n isExpandable?: boolean;\n showTime?: boolean;\n allowWrap?: boolean;\n isSelected?: boolean;\n onSelect?: (index: number, event: React.MouseEvent) => void;\n itemActionButtons?: ReactNode[];\n}\n\nconst DefaultLogRow: React.FC<LogRowProps> = ({\n log,\n isExpanded,\n index,\n onToggle,\n isExpandable = true,\n showTime = false,\n allowWrap = false,\n isSelected = false,\n onSelect,\n itemActionButtons,\n}) => {\n const theme = useTheme();\n const severityColor = useSeverityColor(log);\n const ansiHtml = useMemo(() => (log ? ansiToSanitizedHtml(log.line) : null), [log]);\n const [isHovered, setIsHovered] = useState(false);\n const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);\n const [copySuccess, setCopySuccess] = useState(false);\n const rowRef = useRef<HTMLDivElement>(null);\n const copyTimeoutRef = useRef<number | null>(null);\n\n // Cleanup timeout on unmount\n useEffect(() => {\n return (): void => {\n if (copyTimeoutRef.current) {\n window.clearTimeout(copyTimeoutRef.current);\n }\n };\n }, []);\n\n const handleToggle = useCallback(\n (e: React.MouseEvent) => {\n if (isExpandable) {\n e.stopPropagation();\n onToggle(index);\n }\n },\n [isExpandable, onToggle, index]\n );\n\n const handleRowMouseDown = useCallback(\n (e: React.MouseEvent) => {\n if (onSelect) {\n onSelect(index, e);\n }\n },\n [onSelect, index]\n );\n\n const handleOpenMenu = useCallback((e: React.MouseEvent<HTMLElement>) => {\n e.stopPropagation();\n setAnchorEl(e.currentTarget);\n }, []);\n\n const handleCloseMenu = useCallback(() => {\n setAnchorEl(null);\n setIsHovered(false);\n }, []);\n\n const handleCopy = useCallback(\n async (format: 'full' | 'message' | 'json') => {\n if (!log) return;\n\n let text: string;\n switch (format) {\n case 'message':\n text = formatLogMessage(log);\n break;\n case 'json':\n text = formatLogAsJson(log);\n break;\n case 'full':\n default:\n text = formatLogEntry(log);\n }\n\n await navigator.clipboard.writeText(text);\n setCopySuccess(true);\n handleCloseMenu();\n\n // Clear existing timeout\n if (copyTimeoutRef.current) {\n window.clearTimeout(copyTimeoutRef.current);\n }\n\n // Reset success state after configured duration\n copyTimeoutRef.current = window.setTimeout(() => {\n setCopySuccess(false);\n }, COPY_SUCCESS_DURATION_MS);\n },\n [log, handleCloseMenu]\n );\n\n if (!log) return null;\n\n const hasRowActions = itemActionButtons && itemActionButtons.length > 0;\n\n return (\n <LogRowContainer\n severityColor={severityColor}\n ref={rowRef}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => {\n if (!anchorEl) {\n setIsHovered(false);\n }\n }}\n data-log-index={index}\n data-testid={`log-row-container-${index}`}\n >\n <LogRowContent\n onMouseDown={handleRowMouseDown}\n isExpandable={isExpandable}\n isHighlighted={Boolean(anchorEl)}\n hasRowActions={hasRowActions}\n isSelected={isSelected}\n >\n {isExpandable && (\n <Box\n onClick={handleToggle}\n sx={{\n display: 'flex',\n alignItems: 'center',\n width: '16px',\n justifyContent: 'center',\n cursor: 'pointer',\n }}\n >\n <ExpandButton size=\"small\" isExpanded={isExpanded}>\n <ChevronRight sx={{ fontSize: '12px' }} />\n </ExpandButton>\n </Box>\n )}\n\n <LogTimestamp timestamp={log.timestamp} />\n\n <Box\n sx={{\n display: 'flex',\n gap: '10px',\n marginLeft: '36px',\n alignItems: 'center',\n }}\n >\n {ansiHtml ? (\n <LogText variant=\"body2\" allowWrap={allowWrap} dangerouslySetInnerHTML={{ __html: ansiHtml }} />\n ) : (\n <LogText variant=\"body2\" allowWrap={allowWrap}>\n {log.line}\n </LogText>\n )}\n <Tooltip title={copySuccess ? 'Copied!' : 'Copy options'}>\n <IconButton\n size=\"small\"\n onClick={handleOpenMenu}\n aria-label=\"Copy log options\"\n sx={{\n padding: '4px',\n marginLeft: 'auto',\n color: copySuccess ? theme.palette.success.main : theme.palette.text.secondary,\n opacity: isHovered || Boolean(anchorEl) || copySuccess ? 1 : 0,\n pointerEvents: isHovered || Boolean(anchorEl) || copySuccess ? 'auto' : 'none',\n transition: 'opacity 0.08s ease, color 0.2s ease',\n '&:hover': {\n color: copySuccess ? theme.palette.success.main : theme.palette.primary.main,\n backgroundColor: theme.palette.action.hover,\n },\n borderRadius: '4px',\n display: 'flex',\n gap: '2px',\n }}\n >\n {copySuccess ? (\n <Check sx={{ fontSize: '14px' }} />\n ) : (\n <>\n <ContentCopy sx={{ fontSize: '14px' }} />\n <ChevronDown sx={{ fontSize: '12px' }} />\n </>\n )}\n </IconButton>\n </Tooltip>\n {hasRowActions && (\n <Box\n sx={{\n display: 'flex',\n gap: '4px',\n alignItems: 'center',\n opacity: isHovered || Boolean(anchorEl) ? 1 : 0,\n pointerEvents: isHovered || Boolean(anchorEl) ? 'auto' : 'none',\n transition: 'opacity 0.08s ease',\n }}\n >\n {itemActionButtons}\n </Box>\n )}\n <Menu\n anchorEl={anchorEl}\n open={Boolean(anchorEl)}\n onClose={handleCloseMenu}\n onClick={(e) => e.stopPropagation()}\n aria-label=\"Copy format options\"\n anchorOrigin={{\n vertical: 'bottom',\n horizontal: 'right',\n }}\n transformOrigin={{\n vertical: 'top',\n horizontal: 'right',\n }}\n slotProps={{\n paper: {\n sx: {\n mt: 0.5,\n minWidth: 180,\n boxShadow: theme.shadows[3],\n },\n },\n }}\n >\n <MenuItem\n onClick={() => handleCopy('full')}\n sx={{\n py: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n <ListItemIcon>\n <ContentCopy fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n primary=\"Copy log\"\n secondary=\"Timestamp + labels + message\"\n slotProps={{\n primary: { fontSize: '14px' },\n secondary: { fontSize: '11px' },\n }}\n />\n </MenuItem>\n <MenuItem\n onClick={() => handleCopy('message')}\n sx={{\n py: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n <ListItemIcon>\n <FormatQuoteClose fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n primary=\"Copy message\"\n secondary=\"Message text only\"\n slotProps={{\n primary: { fontSize: '14px' },\n secondary: { fontSize: '11px' },\n }}\n />\n </MenuItem>\n <MenuItem\n onClick={() => handleCopy('json')}\n sx={{\n py: 1,\n '&:hover': {\n backgroundColor: theme.palette.action.hover,\n },\n }}\n >\n <ListItemIcon>\n <CodeJson fontSize=\"small\" />\n </ListItemIcon>\n <ListItemText\n primary=\"Copy as JSON\"\n secondary=\"Full log entry\"\n slotProps={{\n primary: { fontSize: '14px' },\n secondary: { fontSize: '11px' },\n }}\n />\n </MenuItem>\n </Menu>\n </Box>\n </LogRowContent>\n\n <Collapse in={isExpanded} timeout={200}>\n <Box sx={{ padding: '8px' }}>\n <Box\n sx={{\n display: 'grid',\n gridTemplateColumns: !showTime ? '1fr' : '8px minmax(160px, max-content) 1fr',\n gap: '12px',\n }}\n >\n {showTime && (\n <>\n <Box />\n <Box />\n </>\n )}\n <Box>\n <LogDetailsTable log={log.labels} />\n </Box>\n </Box>\n </Box>\n </Collapse>\n </LogRowContainer>\n );\n};\n\nexport const LogRow = memo(DefaultLogRow);\nLogRow.displayName = 'LogRow';\n"],"names":["Box","Collapse","IconButton","ListItemIcon","ListItemText","Menu","MenuItem","Tooltip","useTheme","Check","ChevronDown","ChevronRight","CodeJson","ContentCopy","FormatQuoteClose","React","memo","useCallback","useEffect","useMemo","useRef","useState","ansiToSanitizedHtml","formatLogAsJson","formatLogEntry","formatLogMessage","useSeverityColor","LogDetailsTable","LogTimestamp","ExpandButton","LogRowContainer","LogRowContent","LogText","COPY_SUCCESS_DURATION_MS","DefaultLogRow","log","isExpanded","index","onToggle","isExpandable","showTime","allowWrap","isSelected","onSelect","itemActionButtons","theme","severityColor","ansiHtml","line","isHovered","setIsHovered","anchorEl","setAnchorEl","copySuccess","setCopySuccess","rowRef","copyTimeoutRef","current","window","clearTimeout","handleToggle","e","stopPropagation","handleRowMouseDown","handleOpenMenu","currentTarget","handleCloseMenu","handleCopy","format","text","navigator","clipboard","writeText","setTimeout","hasRowActions","length","ref","onMouseEnter","onMouseLeave","data-log-index","data-testid","onMouseDown","isHighlighted","Boolean","onClick","sx","display","alignItems","width","justifyContent","cursor","size","fontSize","timestamp","gap","marginLeft","variant","dangerouslySetInnerHTML","__html","title","aria-label","padding","color","palette","success","main","secondary","opacity","pointerEvents","transition","primary","backgroundColor","action","hover","borderRadius","open","onClose","anchorOrigin","vertical","horizontal","transformOrigin","slotProps","paper","mt","minWidth","boxShadow","shadows","py","in","timeout","gridTemplateColumns","labels","LogRow","displayName"],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { LogEntry } from '@perses-dev/core';
2
+ import { LogEntry } from '@perses-dev/spec';
3
3
  import { LogsTableOptions } from '../model';
4
4
  interface LogsListProps {
5
5
  logs: LogEntry[];
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/components/LogsList.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 React from 'react';\nimport { LogEntry } from '@perses-dev/core';\nimport { LogsTableOptions } from '../model';\nimport { EmptyLogsState } from './EmptyLogsState';\nimport { useExpandedRows } from './hooks/useExpandedRows';\nimport { VirtualizedLogsList } from './VirtualizedLogsList';\n\ninterface LogsListProps {\n logs: LogEntry[];\n spec: LogsTableOptions;\n}\n\nexport const LogsList: React.FC<LogsListProps> = ({ logs, spec }) => {\n const { expandedRows, toggleExpand } = useExpandedRows();\n\n if (!logs.length) {\n return <EmptyLogsState />;\n }\n\n return <VirtualizedLogsList logs={logs} spec={spec} expandedRows={expandedRows} onToggleExpand={toggleExpand} />;\n};\n"],"names":["React","EmptyLogsState","useExpandedRows","VirtualizedLogsList","LogsList","logs","spec","expandedRows","toggleExpand","length","onToggleExpand"],"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,OAAOA,WAAW,QAAQ;AAG1B,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,mBAAmB,QAAQ,wBAAwB;AAO5D,OAAO,MAAMC,WAAoC,CAAC,EAAEC,IAAI,EAAEC,IAAI,EAAE;IAC9D,MAAM,EAAEC,YAAY,EAAEC,YAAY,EAAE,GAAGN;IAEvC,IAAI,CAACG,KAAKI,MAAM,EAAE;QAChB,qBAAO,KAACR;IACV;IAEA,qBAAO,KAACE;QAAoBE,MAAMA;QAAMC,MAAMA;QAAMC,cAAcA;QAAcG,gBAAgBF;;AAClG,EAAE"}
1
+ {"version":3,"sources":["../../../src/components/LogsList.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 React from 'react';\nimport { LogEntry } from '@perses-dev/spec';\nimport { LogsTableOptions } from '../model';\nimport { EmptyLogsState } from './EmptyLogsState';\nimport { useExpandedRows } from './hooks/useExpandedRows';\nimport { VirtualizedLogsList } from './VirtualizedLogsList';\n\ninterface LogsListProps {\n logs: LogEntry[];\n spec: LogsTableOptions;\n}\n\nexport const LogsList: React.FC<LogsListProps> = ({ logs, spec }) => {\n const { expandedRows, toggleExpand } = useExpandedRows();\n\n if (!logs.length) {\n return <EmptyLogsState />;\n }\n\n return <VirtualizedLogsList logs={logs} spec={spec} expandedRows={expandedRows} onToggleExpand={toggleExpand} />;\n};\n"],"names":["React","EmptyLogsState","useExpandedRows","VirtualizedLogsList","LogsList","logs","spec","expandedRows","toggleExpand","length","onToggleExpand"],"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,OAAOA,WAAW,QAAQ;AAG1B,SAASC,cAAc,QAAQ,mBAAmB;AAClD,SAASC,eAAe,QAAQ,0BAA0B;AAC1D,SAASC,mBAAmB,QAAQ,wBAAwB;AAO5D,OAAO,MAAMC,WAAoC,CAAC,EAAEC,IAAI,EAAEC,IAAI,EAAE;IAC9D,MAAM,EAAEC,YAAY,EAAEC,YAAY,EAAE,GAAGN;IAEvC,IAAI,CAACG,KAAKI,MAAM,EAAE;QAChB,qBAAO,KAACR;IACV;IAEA,qBAAO,KAACE;QAAoBE,MAAMA;QAAMC,MAAMA;QAAMC,cAAcA;QAAcG,gBAAgBF;;AAClG,EAAE"}
@@ -1,5 +1,5 @@
1
1
  import React from 'react';
2
- import { LogEntry } from '@perses-dev/core';
2
+ import { LogEntry } from '@perses-dev/spec';
3
3
  import { LogsTableOptions } from '../model';
4
4
  interface VirtualizedLogsListProps {
5
5
  logs: LogEntry[];
@@ -1 +1 @@
1
- {"version":3,"file":"VirtualizedLogsList.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualizedLogsList.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA8D,MAAM,OAAO,CAAC;AAInF,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAK5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAS5C,UAAU,wBAAwB;IAChC,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,IAAI,EAAE,gBAAgB,CAAC;IACvB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAualE,CAAC"}
1
+ {"version":3,"file":"VirtualizedLogsList.d.ts","sourceRoot":"","sources":["../../../src/components/VirtualizedLogsList.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA8D,MAAM,OAAO,CAAC;AAOnF,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAS5C,UAAU,wBAAwB;IAChC,IAAI,EAAE,QAAQ,EAAE,CAAC;IACjB,IAAI,EAAE,gBAAgB,CAAC;IACvB,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC1B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CACzC;AAED,eAAO,MAAM,mBAAmB,EAAE,KAAK,CAAC,EAAE,CAAC,wBAAwB,CAualE,CAAC"}
@@ -16,14 +16,14 @@ import { Box, useTheme, Popover, Button, ButtonGroup, IconButton } from '@mui/ma
16
16
  import CloseIcon from 'mdi-material-ui/Close';
17
17
  import { Virtuoso } from 'react-virtuoso';
18
18
  import { useSelection } from '@perses-dev/components';
19
- import { useSelectionItemActions } from '@perses-dev/dashboards';
19
+ import { formatForDisplay, useSelectionItemActions } from '@perses-dev/dashboards';
20
20
  import { useAllVariableValues } from '@perses-dev/plugin-system';
21
21
  import { formatLogEntries, formatLogMessage } from '../utils/copyHelpers';
22
22
  import { LogRow } from './LogRow';
23
23
  const PERSES_LOGSTABLE_HINTS_DISMISSED = 'PERSES_LOGSTABLE_HINTS_DISMISSED';
24
24
  const COPY_TOAST_DURATION_MS = 5000;
25
- // Detect Mac for keyboard shortcuts display
26
- const isMac = /(Mac|iPhone|iPod|iPad)/i.test(navigator.userAgent);
25
+ // Platform-aware modifier key display using TanStack's formatForDisplay
26
+ const modKeyDisplay = formatForDisplay('Mod');
27
27
  export const VirtualizedLogsList = ({ logs, spec, expandedRows, onToggleExpand })=>{
28
28
  const theme = useTheme();
29
29
  const [selectedRows, setSelectedRows] = useState(new Set());
@@ -295,7 +295,7 @@ export const VirtualizedLogsList = ({ logs, spec, expandedRows, onToggleExpand }
295
295
  opacity: 0.8
296
296
  },
297
297
  children: [
298
- isMac ? '⌘' : 'Ctrl',
298
+ modKeyDisplay,
299
299
  "+Click to select"
300
300
  ]
301
301
  }),
@@ -326,7 +326,7 @@ export const VirtualizedLogsList = ({ logs, spec, expandedRows, onToggleExpand }
326
326
  opacity: 0.8
327
327
  },
328
328
  children: [
329
- isMac ? '⌘' : 'Ctrl',
329
+ modKeyDisplay,
330
330
  "+C to copy"
331
331
  ]
332
332
  }),