@kylincloud/flamegraph 0.35.27 → 0.35.28

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 (37) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/FlameGraph/FlameGraphComponent/DiffLegend.d.ts.map +1 -1
  3. package/dist/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.d.ts.map +1 -1
  4. package/dist/FlameGraph/FlameGraphComponent/index.d.ts.map +1 -1
  5. package/dist/Icons.d.ts.map +1 -1
  6. package/dist/SharedQueryInput.d.ts.map +1 -1
  7. package/dist/Toolbar.d.ts.map +1 -1
  8. package/dist/index.cjs.js +4 -4
  9. package/dist/index.cjs.js.map +1 -1
  10. package/dist/index.esm.js +4 -4
  11. package/dist/index.esm.js.map +1 -1
  12. package/dist/index.node.cjs.js +2 -2
  13. package/dist/index.node.cjs.js.map +1 -1
  14. package/dist/index.node.esm.js +4 -4
  15. package/dist/index.node.esm.js.map +1 -1
  16. package/dist/shims/Table.d.ts.map +1 -1
  17. package/dist/shims/Tooltip.d.ts.map +1 -1
  18. package/package.json +1 -1
  19. package/src/FlameGraph/FlameGraphComponent/DiffLegend.module.css +8 -2
  20. package/src/FlameGraph/FlameGraphComponent/DiffLegend.tsx +12 -1
  21. package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.module.css +93 -10
  22. package/src/FlameGraph/FlameGraphComponent/DiffLegendPaletteDropdown.tsx +9 -4
  23. package/src/FlameGraph/FlameGraphComponent/index.tsx +58 -56
  24. package/src/FlameGraph/FlameGraphComponent/styles.module.scss +8 -0
  25. package/src/Icons.tsx +18 -9
  26. package/src/SharedQueryInput.module.scss +50 -0
  27. package/src/SharedQueryInput.tsx +18 -3
  28. package/src/Toolbar.module.scss +90 -0
  29. package/src/Toolbar.tsx +30 -16
  30. package/src/i18n.tsx +1 -1
  31. package/src/sass/_common.scss +22 -3
  32. package/src/sass/_css-variables.scss +5 -1
  33. package/src/sass/flamegraph.scss +26 -23
  34. package/src/shims/Table.module.scss +86 -13
  35. package/src/shims/Table.tsx +7 -2
  36. package/src/shims/Tooltip.module.scss +40 -0
  37. package/src/shims/Tooltip.tsx +31 -3
package/src/Toolbar.tsx CHANGED
@@ -7,6 +7,7 @@ import React, {
7
7
  useLayoutEffect,
8
8
  isValidElement,
9
9
  memo,
10
+ useEffect,
10
11
  } from 'react';
11
12
  import classNames from 'classnames/bind';
12
13
  import { faUndo } from '@fortawesome/free-solid-svg-icons/faUndo';
@@ -170,8 +171,21 @@ const Toolbar = memo(
170
171
  setPalette,
171
172
  }: ProfileHeaderProps) => {
172
173
  const toolbarRef = useRef<HTMLDivElement>(null);
174
+ const [isKylin, setIsKylin] = useState(false);
173
175
  const i18n = useFlamegraphI18n();
174
176
 
177
+ useEffect(() => {
178
+ const el = toolbarRef.current;
179
+ if (!el) return;
180
+ const kylinEl = el.closest(
181
+ "[data-theme='kylin'], [data-flamegraph-color-mode='kylin']"
182
+ );
183
+ setIsKylin(!!kylinEl);
184
+ }, []);
185
+
186
+ const toolbarSquareWidth = isKylin ? 32 : TOOLBAR_SQUARE_WIDTH;
187
+ const queryInputWidth = isKylin ? 220 : QUERY_INPUT_WIDTH;
188
+
175
189
  // 是否显示调色板选择器(仅在 diff 模式且有 palette 时显示)
176
190
  const showPaletteDropdown = flamegraphType === 'double' && palette && setPalette;
177
191
 
@@ -182,11 +196,11 @@ const Toolbar = memo(
182
196
  <Divider />
183
197
  </>
184
198
  ),
185
- width: TOOLBAR_SQUARE_WIDTH * 2 + DIVIDER_WIDTH,
199
+ width: toolbarSquareWidth * 2 + DIVIDER_WIDTH,
186
200
  };
187
201
  const resetItem = {
188
202
  el: <ResetView isFlamegraphDirty={isFlamegraphDirty} reset={reset} />,
189
- width: TOOLBAR_SQUARE_WIDTH,
203
+ width: toolbarSquareWidth,
190
204
  };
191
205
  const focusOnSubtree = {
192
206
  el: (
@@ -198,7 +212,7 @@ const Toolbar = memo(
198
212
  <Divider />
199
213
  </>
200
214
  ),
201
- width: TOOLBAR_SQUARE_WIDTH + DIVIDER_WIDTH,
215
+ width: toolbarSquareWidth + DIVIDER_WIDTH,
202
216
  };
203
217
 
204
218
  const viewSectionItem = enableChangingDisplay
@@ -210,7 +224,7 @@ const Toolbar = memo(
210
224
  updateView={updateView}
211
225
  />
212
226
  ),
213
- width: TOOLBAR_SQUARE_WIDTH * (flamegraphType === 'single' ? 5 : 3),
227
+ width: toolbarSquareWidth * (flamegraphType === 'single' ? 5 : 3),
214
228
  }
215
229
  : null;
216
230
  const exportDataItem = isValidElement(ExportData)
@@ -221,7 +235,7 @@ const Toolbar = memo(
221
235
  {ExportData}
222
236
  </>
223
237
  ),
224
- width: TOOLBAR_SQUARE_WIDTH + DIVIDER_WIDTH,
238
+ width: toolbarSquareWidth + DIVIDER_WIDTH,
225
239
  }
226
240
  : null;
227
241
 
@@ -261,7 +275,7 @@ const Toolbar = memo(
261
275
  {/* 左侧:搜索框 */}
262
276
  <div className={styles.searchWrapper}>
263
277
  <SharedQueryInput
264
- width={QUERY_INPUT_WIDTH}
278
+ width={queryInputWidth}
265
279
  onHighlightChange={handleSearchChange}
266
280
  highlightQuery={highlightQuery}
267
281
  sharedQuery={sharedQuery}
@@ -430,17 +444,17 @@ const getViewOptions = (
430
444
  }> =>
431
445
  flamegraphType === 'single'
432
446
  ? [
447
+ {
448
+ label: messages.viewFlamegraph,
449
+ value: 'flamegraph',
450
+ Icon: FlamegraphIcon,
451
+ },
433
452
  { label: messages.viewTable, value: 'table', Icon: TableIcon },
434
453
  {
435
454
  label: messages.viewTableAndFlamegraph,
436
455
  value: 'both',
437
456
  Icon: TablePlusFlamegraphIcon,
438
457
  },
439
- {
440
- label: messages.viewFlamegraph,
441
- value: 'flamegraph',
442
- Icon: FlamegraphIcon,
443
- },
444
458
  { label: messages.viewSandwich, value: 'sandwich', Icon: SandwichIcon },
445
459
  {
446
460
  label: messages.viewGraphviz,
@@ -449,17 +463,17 @@ const getViewOptions = (
449
463
  },
450
464
  ]
451
465
  : [
466
+ {
467
+ label: messages.viewFlamegraph,
468
+ value: 'flamegraph',
469
+ Icon: FlamegraphIcon,
470
+ },
452
471
  { label: messages.viewTable, value: 'table', Icon: TableIcon },
453
472
  {
454
473
  label: messages.viewTableAndFlamegraph,
455
474
  value: 'both',
456
475
  Icon: TablePlusFlamegraphIcon,
457
476
  },
458
- {
459
- label: messages.viewFlamegraph,
460
- value: 'flamegraph',
461
- Icon: FlamegraphIcon,
462
- },
463
477
  ];
464
478
 
465
479
  function ViewSection({
package/src/i18n.tsx CHANGED
@@ -296,7 +296,7 @@ export const zhCNMessages: FlamegraphMessages = {
296
296
  diffLegendAddedLabel: '增加 (+)',
297
297
  diffLegendSelectPalette: '选择颜色方案',
298
298
  paletteDefaultName: '默认',
299
- paletteColorBlindName: '色盲模式',
299
+ paletteColorBlindName: '色盲',
300
300
  // 调色板补充描述(中文)
301
301
  paletteDefaultDesc: '(绿色 → 红色)',
302
302
  paletteColorBlindDesc: '(蓝色 → 红色)',
@@ -131,9 +131,8 @@ tt {
131
131
  padding: 6px 10px;
132
132
  }
133
133
 
134
- tr th,
135
- tr:nth-child(2n) td {
136
- background: var(--ps-neutral-9);
134
+ thead th {
135
+ background: var(--ps-table-header-bg, var(--ps-ui-foreground, #ffffff));
137
136
  }
138
137
 
139
138
  td {
@@ -182,3 +181,23 @@ tt {
182
181
  }
183
182
  }
184
183
  }
184
+
185
+ // Kylin theme table density tweaks to match Insights UI
186
+ :global([data-theme='kylin']) {
187
+ .flamegraph-table {
188
+ font-size: 12px;
189
+ border-color: #d9d9d9;
190
+ }
191
+
192
+ .flamegraph-table th {
193
+ padding: 6px 8px;
194
+ border-left-color: #d9d9d9;
195
+ border-bottom-color: #d9d9d9;
196
+ }
197
+
198
+ .flamegraph-table td {
199
+ padding: 4px 8px;
200
+ border-left-color: #f0f0f0;
201
+ border-bottom-color: #f0f0f0;
202
+ }
203
+ }
@@ -57,6 +57,8 @@
57
57
  // 表头(使用实心背景,避免 sticky 时透出内容)
58
58
  --ps-table-header-bg: #212124;
59
59
  --ps-table-header-text: #d8d8d8;
60
+ --ps-table-sort-icon: #9a9aa0;
61
+ --ps-table-sort-icon-active: var(--ps-button-switch-bg-highlight);
60
62
 
61
63
  // 选择器
62
64
  --ps-selected-app: #df8b53;
@@ -209,6 +211,8 @@
209
211
  --ps-tooltip-header-bg: #f0f0f0;
210
212
 
211
213
  // 表头专用:完全不透明的白色
212
- --ps-table-header-bg: #ffffff;
214
+ --ps-table-header-bg: #fafafa;
213
215
  --ps-table-header-text: #000000;
216
+ --ps-table-sort-icon: #bfbfbf;
217
+ --ps-table-sort-icon-active: #5d976f;
214
218
  }
@@ -29,43 +29,41 @@ pyro-flamegraph {
29
29
 
30
30
  /* 只在差分火焰图(double)模式下启用滚动限制 */
31
31
  /* 把滚动交给 tbody,表头固定在表格上方 */
32
- .flamegraph-table-wrapper--double .flamegraph-table-scroll {
32
+ .flamegraph-table-wrapper--double {
33
+ border: 1px solid var(--ps-ui-border);
34
+ border-radius: 6px;
33
35
  overflow: hidden;
34
- position: relative;
35
- }
36
-
37
- .flamegraph-table-wrapper--double .flamegraph-table-scroll table {
38
- width: 100%;
39
- table-layout: fixed;
36
+ background-color: var(--ps-ui-foreground, #fff);
37
+ min-height: var(--kylin-flamegraph-pane-min-height, 320px);
40
38
  }
41
39
 
42
- .flamegraph-table-wrapper--double .flamegraph-table-scroll thead {
43
- display: table;
44
- width: calc(100% - var(--kylin-flamegraph-scrollbar-size, 0px));
45
- table-layout: fixed;
40
+ .flamegraph-table-wrapper--double .flamegraph-table {
41
+ border: none;
46
42
  }
47
43
 
48
- .flamegraph-table-wrapper--double .flamegraph-table-scroll tbody {
49
- display: block;
50
- max-height: var(--kylin-flamegraph-table-max-height, 1000px);
51
- overflow-y: scroll;
44
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll {
52
45
  overflow-x: hidden;
53
- scrollbar-gutter: stable;
46
+ overflow-y: auto;
47
+ position: relative;
48
+ max-height: var(--kylin-flamegraph-table-max-height, 1000px);
54
49
  }
55
50
 
56
- .flamegraph-table-wrapper--double .flamegraph-table-scroll tbody tr {
57
- display: table;
51
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll table {
58
52
  width: 100%;
59
53
  table-layout: fixed;
60
54
  }
61
55
 
62
- /* 表头固定 + 不透明背景,避免内容透出来 */
63
56
  .flamegraph-table-wrapper--double .flamegraph-table-scroll thead {
57
+ display: table-header-group;
64
58
  position: sticky;
65
59
  top: 0;
66
60
  z-index: 3; // 比下面的行和 tooltip 都高一点
67
61
  }
68
62
 
63
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll tbody {
64
+ display: table-row-group;
65
+ }
66
+
69
67
  /* 整行都有底色,避免列间缝隙透出内容 */
70
68
  .flamegraph-table-wrapper--double .flamegraph-table-scroll thead tr {
71
69
  background-color: var(--ps-table-header-bg, var(--ps-ui-foreground, #ffffff));
@@ -85,14 +83,19 @@ pyro-flamegraph {
85
83
 
86
84
  /* 可选:稍微美化一下内部滚动条,轨道透明,避免太抢眼 */
87
85
  .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar {
88
- width: 8px;
86
+ width: 6px;
89
87
  }
90
88
 
91
89
  .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar-track {
92
- background: transparent;
90
+ background: #f5f5f5;
91
+ border-radius: 6px;
93
92
  }
94
93
 
95
94
  .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar-thumb {
96
- background-color: rgba(0, 0, 0, 0.18);
97
- border-radius: 4px;
95
+ background-color: #bfbfbf;
96
+ border-radius: 6px;
97
+ }
98
+
99
+ .flamegraph-table-wrapper--double .flamegraph-table-scroll::-webkit-scrollbar-thumb:hover {
100
+ background-color: #8c8c8c;
98
101
  }
@@ -21,23 +21,23 @@
21
21
  top: 3px;
22
22
  position: relative;
23
23
  margin-left: 7px;
24
+ }
24
25
 
25
- &.asc {
26
- border-top-color: transparent;
27
- border-bottom-color: var(--ps-button-switch-bg-highlight);
28
- top: -2px;
29
- }
26
+ .sortArrowUp,
27
+ .sortArrowDown {
28
+ display: none;
29
+ }
30
30
 
31
- &.desc {
32
- border-top-color: var(--ps-button-switch-bg-highlight);
33
- top: 3px;
34
- }
31
+ .sortArrow.asc {
32
+ border-top-color: transparent;
33
+ border-bottom-color: var(--ps-button-switch-bg-highlight);
34
+ top: -2px;
35
35
  }
36
- }
37
36
 
38
- /* 斑马纹只应用在 tbody 行,不再影响 thead */
39
- tbody tr:nth-child(2n) {
40
- background-color: var(--ps-neutral-9);
37
+ .sortArrow.desc {
38
+ border-top-color: var(--ps-button-switch-bg-highlight);
39
+ top: 3px;
40
+ }
41
41
  }
42
42
 
43
43
  tbody {
@@ -83,6 +83,79 @@
83
83
  }
84
84
  }
85
85
 
86
+ :global([data-theme='kylin']) {
87
+ .table {
88
+ thead th {
89
+ text-align: left;
90
+ background: #fafafa;
91
+ border-color: #d9d9d9;
92
+ }
93
+
94
+ tbody td {
95
+ border-color: #f0f0f0;
96
+ }
97
+
98
+ tbody tr:not(.isRowSelected):hover {
99
+ background: #f5f5f5;
100
+ color: var(--ps-neutral-2);
101
+ }
102
+
103
+ thead th {
104
+ &.sortable {
105
+ position: relative;
106
+ padding-right: 18px;
107
+ }
108
+
109
+ .sortArrow {
110
+ display: inline-flex;
111
+ flex-direction: column;
112
+ margin-left: 6px;
113
+ line-height: 1;
114
+ border: 0;
115
+ position: absolute;
116
+ right: 6px;
117
+ top: 50%;
118
+ transform: translateY(-50%);
119
+ vertical-align: middle;
120
+ }
121
+
122
+ .sortArrowUp,
123
+ .sortArrowDown {
124
+ display: inline-block;
125
+ width: 0;
126
+ height: 0;
127
+ border-left: 4px solid transparent;
128
+ border-right: 4px solid transparent;
129
+ opacity: 0.35;
130
+ }
131
+
132
+ .sortArrowUp {
133
+ border-bottom: 5px solid var(--ps-table-sort-icon, var(--ps-ui-foreground-text));
134
+ margin-bottom: 2px;
135
+ }
136
+
137
+ .sortArrowDown {
138
+ border-top: 5px solid var(--ps-table-sort-icon, var(--ps-ui-foreground-text));
139
+ }
140
+
141
+ .sortArrow.active .sortArrowUp,
142
+ .sortArrow.active .sortArrowDown {
143
+ opacity: 0.45;
144
+ }
145
+
146
+ .sortArrow.asc .sortArrowUp {
147
+ border-bottom-color: var(--ps-table-sort-icon-active, var(--ps-button-switch-bg-highlight));
148
+ opacity: 1;
149
+ }
150
+
151
+ .sortArrow.desc .sortArrowDown {
152
+ border-top-color: var(--ps-table-sort-icon-active, var(--ps-button-switch-bg-highlight));
153
+ opacity: 1;
154
+ }
155
+ }
156
+ }
157
+ }
158
+
86
159
  .table:global(.flamegraph-table-doubles) {
87
160
  th:first-child,
88
161
  td:first-child {
@@ -179,9 +179,14 @@ function Table({
179
179
  {label}
180
180
  <span
181
181
  className={clsx(styles.sortArrow, {
182
- [styles[sortByDirection]]: sortBy === name,
182
+ [styles.active]: sortBy === name,
183
+ [styles.asc]: sortBy === name && sortByDirection === 'asc',
184
+ [styles.desc]: sortBy === name && sortByDirection === 'desc',
183
185
  })}
184
- />
186
+ >
187
+ <span className={styles.sortArrowUp} />
188
+ <span className={styles.sortArrowDown} />
189
+ </span>
185
190
  </th>
186
191
  )
187
192
  )}
@@ -0,0 +1,40 @@
1
+ .tooltipWrapper {
2
+ position: relative;
3
+ display: inline-flex;
4
+ align-items: center;
5
+ }
6
+
7
+ .tooltipBubble {
8
+ position: absolute;
9
+ left: 50%;
10
+ bottom: 100%;
11
+ transform: translate(-50%, -8px);
12
+ padding: 6px 10px;
13
+ border-radius: 4px;
14
+ background: rgba(0, 0, 0, 0.85);
15
+ color: #ffffff;
16
+ font-size: 12px;
17
+ line-height: 1.4;
18
+ white-space: nowrap;
19
+ pointer-events: none;
20
+ opacity: 0;
21
+ transition: opacity 120ms ease, transform 120ms ease;
22
+ z-index: 5;
23
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
24
+ }
25
+
26
+ .tooltipArrow {
27
+ position: absolute;
28
+ left: 50%;
29
+ top: 100%;
30
+ transform: translate(-50%, -2px);
31
+ border-width: 6px 6px 0 6px;
32
+ border-style: solid;
33
+ border-color: rgba(0, 0, 0, 0.85) transparent transparent transparent;
34
+ pointer-events: none;
35
+ }
36
+
37
+ .tooltipWrapper:hover .tooltipBubble {
38
+ opacity: 1;
39
+ transform: translate(-50%, -14px);
40
+ }
@@ -1,5 +1,6 @@
1
1
  // src/shims/Tooltip.tsx
2
- import React from 'react'
2
+ import React, { useEffect, useRef, useState } from 'react'
3
+ import styles from './Tooltip.module.scss'
3
4
 
4
5
  export interface TooltipProps {
5
6
  placement?: string
@@ -34,18 +35,45 @@ function nodeToPlainText(node: React.ReactNode): string | undefined {
34
35
  }
35
36
 
36
37
  export const Tooltip: React.FC<TooltipProps> = ({
37
- placement, // 目前不用,但保留参数以兼容原版
38
+ placement, // 目前只处理 top
38
39
  title,
39
40
  content,
40
41
  children,
41
42
  }) => {
42
43
  const text = title ?? content
43
44
  const titleStr = nodeToPlainText(text)
45
+ const wrapperRef = useRef<HTMLSpanElement | null>(null)
46
+ const [isKylin, setIsKylin] = useState(false)
47
+
48
+ useEffect(() => {
49
+ const el = wrapperRef.current
50
+ if (!el) return
51
+ const kylinEl = el.closest(
52
+ "[data-theme='kylin'], [data-flamegraph-color-mode='kylin']"
53
+ )
54
+ setIsKylin(!!kylinEl)
55
+ }, [])
44
56
 
45
57
  // 没有文本就不加 title,避免空 tooltip
46
58
  if (!titleStr) {
47
59
  return <>{children}</>
48
60
  }
49
61
 
50
- return <span title={titleStr}>{children}</span>
62
+ return (
63
+ <span
64
+ ref={wrapperRef}
65
+ className={styles.tooltipWrapper}
66
+ data-placement={placement || 'top'}
67
+ data-tooltip={isKylin ? titleStr : undefined}
68
+ title={isKylin ? undefined : titleStr}
69
+ >
70
+ {children}
71
+ {isKylin ? (
72
+ <span className={styles.tooltipBubble} role="tooltip">
73
+ {titleStr}
74
+ <span className={styles.tooltipArrow} />
75
+ </span>
76
+ ) : null}
77
+ </span>
78
+ )
51
79
  }