@parca/profile 0.16.444 → 0.16.446
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +8 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +9 -2
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +3 -11
- package/dist/ProfileView/ColorStackLegend.d.ts.map +1 -0
- package/dist/{ProfileIcicleGraph/IcicleGraphArrow → ProfileView}/ColorStackLegend.js +2 -2
- package/dist/ProfileView/VisualizationPanel.d.ts +4 -1
- package/dist/ProfileView/VisualizationPanel.d.ts.map +1 -1
- package/dist/ProfileView/VisualizationPanel.js +4 -6
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +33 -10
- package/dist/ProfileViewWithData.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +1 -3
- package/dist/Table/index.d.ts +2 -29
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +65 -160
- package/dist/Table/utils/functions.d.ts +49 -0
- package/dist/Table/utils/functions.d.ts.map +1 -0
- package/dist/Table/utils/functions.js +181 -0
- package/dist/components/ActionButtons/GroupByDropdown.js +1 -1
- package/dist/components/ActionButtons/SortByDropdown.d.ts +3 -0
- package/dist/components/ActionButtons/SortByDropdown.d.ts.map +1 -0
- package/dist/components/ActionButtons/SortByDropdown.js +49 -0
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts.map +1 -1
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.js +3 -27
- package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts.map +1 -1
- package/dist/components/VisualisationToolbar/TableColumnsDropdown.js +3 -1
- package/dist/components/VisualisationToolbar/index.d.ts +11 -0
- package/dist/components/VisualisationToolbar/index.d.ts.map +1 -1
- package/dist/components/VisualisationToolbar/index.js +13 -6
- package/dist/styles.css +1 -1
- package/package.json +3 -3
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +19 -2
- package/src/ProfileIcicleGraph/index.tsx +2 -18
- package/src/{ProfileIcicleGraph/IcicleGraphArrow → ProfileView}/ColorStackLegend.tsx +2 -2
- package/src/ProfileView/VisualizationPanel.tsx +13 -10
- package/src/ProfileView/index.tsx +59 -9
- package/src/ProfileViewWithData.tsx +1 -3
- package/src/Table/index.tsx +138 -265
- package/src/Table/utils/functions.ts +284 -0
- package/src/components/ActionButtons/GroupByDropdown.tsx +1 -1
- package/src/components/ActionButtons/SortByDropdown.tsx +84 -0
- package/src/components/VisualisationToolbar/MultiLevelDropdown.tsx +7 -30
- package/src/components/VisualisationToolbar/TableColumnsDropdown.tsx +3 -1
- package/src/components/VisualisationToolbar/index.tsx +103 -58
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.d.ts.map +0 -1
- /package/dist/{ProfileIcicleGraph/IcicleGraphArrow → ProfileView}/ColorStackLegend.d.ts +0 -0
package/src/Table/index.tsx
CHANGED
|
@@ -32,11 +32,36 @@ import {
|
|
|
32
32
|
useURLState,
|
|
33
33
|
} from '@parca/components';
|
|
34
34
|
import {type RowRendererProps} from '@parca/components/dist/Table';
|
|
35
|
+
import {useCurrentColorProfile} from '@parca/hooks';
|
|
35
36
|
import {ProfileType} from '@parca/parser';
|
|
36
|
-
import {
|
|
37
|
+
import {isSearchMatch, valueFormatter} from '@parca/utilities';
|
|
37
38
|
|
|
39
|
+
import {getFilenameColors, getMappingColors} from '../ProfileIcicleGraph/IcicleGraphArrow/';
|
|
40
|
+
import {colorByColors} from '../ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes';
|
|
41
|
+
import useMappingList, {
|
|
42
|
+
useFilenamesList,
|
|
43
|
+
} from '../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
|
|
38
44
|
import {useProfileViewContext} from '../ProfileView/ProfileViewContext';
|
|
39
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
ColumnName,
|
|
47
|
+
DataRow,
|
|
48
|
+
DummyRow,
|
|
49
|
+
ROW_HEIGHT,
|
|
50
|
+
RowName,
|
|
51
|
+
addPlusSign,
|
|
52
|
+
getCalleeRows,
|
|
53
|
+
getCallerRows,
|
|
54
|
+
getRowColor,
|
|
55
|
+
getScrollTargetIndex,
|
|
56
|
+
isFirstSubRow,
|
|
57
|
+
isLastSubRow,
|
|
58
|
+
isSubRow,
|
|
59
|
+
ratioString,
|
|
60
|
+
rowBgClassNames,
|
|
61
|
+
sizeToBottomStyle,
|
|
62
|
+
sizeToHeightStyle,
|
|
63
|
+
sizeToWidthStyle,
|
|
64
|
+
} from './utils/functions';
|
|
40
65
|
import {getTopAndBottomExpandedRowModel} from './utils/topAndBottomExpandedRowModel';
|
|
41
66
|
|
|
42
67
|
const FIELD_MAPPING_FILE = 'mapping_file';
|
|
@@ -51,30 +76,6 @@ const FIELD_CUMULATIVE_DIFF = 'cumulative_diff';
|
|
|
51
76
|
const FIELD_CALLERS = 'callers';
|
|
52
77
|
const FIELD_CALLEES = 'callees';
|
|
53
78
|
|
|
54
|
-
export interface DataRow {
|
|
55
|
-
id: number;
|
|
56
|
-
name: string;
|
|
57
|
-
flat: bigint;
|
|
58
|
-
flatDiff: bigint;
|
|
59
|
-
cumulative: bigint;
|
|
60
|
-
cumulativeDiff: bigint;
|
|
61
|
-
mappingFile: string;
|
|
62
|
-
functionSystemName: string;
|
|
63
|
-
functionFileName: string;
|
|
64
|
-
callers?: DataRow[];
|
|
65
|
-
callees?: DataRow[];
|
|
66
|
-
subRows?: Row[];
|
|
67
|
-
isTopSubRow?: boolean;
|
|
68
|
-
isBottomSubRow?: boolean;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
interface DummyRow {
|
|
72
|
-
size: number;
|
|
73
|
-
message?: string;
|
|
74
|
-
isTopSubRow?: boolean;
|
|
75
|
-
isBottomSubRow?: boolean;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
79
|
export type Row = DataRow | DummyRow;
|
|
79
80
|
|
|
80
81
|
export const isDummyRow = (row: Row): row is DummyRow => {
|
|
@@ -94,50 +95,9 @@ interface TableProps {
|
|
|
94
95
|
setActionButtons?: (buttons: React.JSX.Element) => void;
|
|
95
96
|
isHalfScreen: boolean;
|
|
96
97
|
unit?: string;
|
|
98
|
+
metadataMappingFiles?: string[];
|
|
97
99
|
}
|
|
98
100
|
|
|
99
|
-
export type ColumnName =
|
|
100
|
-
| 'flat'
|
|
101
|
-
| 'flatPercentage'
|
|
102
|
-
| 'flatDiff'
|
|
103
|
-
| 'flatDiffPercentage'
|
|
104
|
-
| 'cumulative'
|
|
105
|
-
| 'cumulativePercentage'
|
|
106
|
-
| 'cumulativeDiff'
|
|
107
|
-
| 'cumulativeDiffPercentage'
|
|
108
|
-
| 'name'
|
|
109
|
-
| 'functionSystemName'
|
|
110
|
-
| 'functionFileName'
|
|
111
|
-
| 'mappingFile';
|
|
112
|
-
|
|
113
|
-
const rowBgClassNames = (isExpanded: boolean, isSubRow: boolean): Record<string, boolean> => {
|
|
114
|
-
return {
|
|
115
|
-
relative: true,
|
|
116
|
-
'bg-indigo-100 dark:bg-gray-600': isSubRow,
|
|
117
|
-
'bg-indigo-50 dark:bg-gray-700': isExpanded,
|
|
118
|
-
};
|
|
119
|
-
};
|
|
120
|
-
|
|
121
|
-
const ROW_HEIGHT = 29;
|
|
122
|
-
|
|
123
|
-
const sizeToHeightStyle = (size: number): Record<string, string> => {
|
|
124
|
-
return {
|
|
125
|
-
height: `${size * ROW_HEIGHT}px`,
|
|
126
|
-
};
|
|
127
|
-
};
|
|
128
|
-
|
|
129
|
-
const sizeToWidthStyle = (size: number): Record<string, string> => {
|
|
130
|
-
return {
|
|
131
|
-
width: `${size * ROW_HEIGHT}px`,
|
|
132
|
-
};
|
|
133
|
-
};
|
|
134
|
-
|
|
135
|
-
const sizeToBottomStyle = (size: number): Record<string, string> => {
|
|
136
|
-
return {
|
|
137
|
-
bottom: `-${size * ROW_HEIGHT}px`,
|
|
138
|
-
};
|
|
139
|
-
};
|
|
140
|
-
|
|
141
101
|
const CustomRowRenderer = ({
|
|
142
102
|
row,
|
|
143
103
|
usePointerCursor,
|
|
@@ -241,13 +201,13 @@ const CustomRowRenderer = ({
|
|
|
241
201
|
{idx === 0 && isExpanded ? (
|
|
242
202
|
<>
|
|
243
203
|
<div
|
|
244
|
-
className={`absolute top-0 left-0 bg-white dark:bg-indigo-500 px-1 uppercase -rotate-90 origin-top-left z-
|
|
204
|
+
className={`absolute top-0 left-0 bg-white dark:bg-indigo-500 px-1 uppercase -rotate-90 origin-top-left z-[9] text-[10px] border-l border-y border-gray-200 dark:border-gray-700 text-left`}
|
|
245
205
|
style={{...sizeToWidthStyle(3)}}
|
|
246
206
|
>
|
|
247
207
|
Callers {'->'}
|
|
248
208
|
</div>
|
|
249
209
|
<div
|
|
250
|
-
className={`absolute left-[18px] bg-white dark:bg-indigo-500 px-1 uppercase -rotate-90 origin-bottom-left z-
|
|
210
|
+
className={`absolute left-[18px] bg-white dark:bg-indigo-500 px-1 uppercase -rotate-90 origin-bottom-left z-[9] text-[10px] border-r border-y border-gray-200 dark:border-gray-700`}
|
|
251
211
|
style={{
|
|
252
212
|
...sizeToWidthStyle(3),
|
|
253
213
|
...sizeToBottomStyle(3),
|
|
@@ -266,68 +226,6 @@ const CustomRowRenderer = ({
|
|
|
266
226
|
);
|
|
267
227
|
};
|
|
268
228
|
|
|
269
|
-
const getCallerRows = (callers: DataRow[]): Row[] => {
|
|
270
|
-
if (callers.length === 0) {
|
|
271
|
-
return [{size: 3, message: 'No callers.', isTopSubRow: true}];
|
|
272
|
-
}
|
|
273
|
-
|
|
274
|
-
const rows = callers.map(row => {
|
|
275
|
-
return {...row, isTopSubRow: true};
|
|
276
|
-
});
|
|
277
|
-
if (rows.length >= 3) {
|
|
278
|
-
return rows;
|
|
279
|
-
}
|
|
280
|
-
|
|
281
|
-
return [...rows, {size: 3 - rows.length, message: '', isTopSubRow: true}];
|
|
282
|
-
};
|
|
283
|
-
|
|
284
|
-
const getCalleeRows = (callees: DataRow[]): Row[] => {
|
|
285
|
-
if (callees.length === 0) {
|
|
286
|
-
return [{size: 3, message: 'No callees.', isBottomSubRow: true}];
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
const rows = callees.map(row => {
|
|
290
|
-
return {...row, isBottomSubRow: true};
|
|
291
|
-
});
|
|
292
|
-
if (rows.length >= 3) {
|
|
293
|
-
return rows;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
return [{size: 3 - rows.length, message: '', isBottomSubRow: true}, ...rows];
|
|
297
|
-
};
|
|
298
|
-
|
|
299
|
-
export const getPercentageString = (value: bigint | number, total: bigint | number): string => {
|
|
300
|
-
if (total === 0n) {
|
|
301
|
-
return '0%';
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
const percentage = (Number(value) / Number(total)) * 100;
|
|
305
|
-
return `${percentage.toFixed(2)}%`;
|
|
306
|
-
};
|
|
307
|
-
|
|
308
|
-
export const getRatioString = (value: bigint | number, total: bigint, filtered: bigint): string => {
|
|
309
|
-
if (filtered === 0n) {
|
|
310
|
-
return ` ${getPercentageString(value, total)}`;
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
return `${getPercentageString(value, total)} / ${getPercentageString(value, filtered)}`;
|
|
314
|
-
};
|
|
315
|
-
|
|
316
|
-
export const possibleColumns = [
|
|
317
|
-
'flat',
|
|
318
|
-
'flatPercentage',
|
|
319
|
-
'flatDiff',
|
|
320
|
-
'flatDiffPercentage',
|
|
321
|
-
'cumulative',
|
|
322
|
-
'cumulativePercentage',
|
|
323
|
-
'cumulativeDiff',
|
|
324
|
-
'cumulativeDiffPercentage',
|
|
325
|
-
'name',
|
|
326
|
-
'functionSystemName',
|
|
327
|
-
'functionFileName',
|
|
328
|
-
'mappingFile',
|
|
329
|
-
];
|
|
330
|
-
|
|
331
229
|
export const Table = React.memo(function Table({
|
|
332
230
|
data,
|
|
333
231
|
total,
|
|
@@ -338,43 +236,82 @@ export const Table = React.memo(function Table({
|
|
|
338
236
|
setSearchString = () => {},
|
|
339
237
|
isHalfScreen,
|
|
340
238
|
unit,
|
|
239
|
+
metadataMappingFiles,
|
|
341
240
|
}: TableProps): React.JSX.Element {
|
|
241
|
+
const currentColorProfile = useCurrentColorProfile();
|
|
342
242
|
const [dashboardItems] = useURLState<string[]>('dashboard_items', {
|
|
343
243
|
alwaysReturnArray: true,
|
|
344
244
|
});
|
|
245
|
+
|
|
345
246
|
const [tableColumns] = useURLState<string[]>('table_columns', {
|
|
346
247
|
alwaysReturnArray: true,
|
|
347
248
|
});
|
|
348
|
-
|
|
249
|
+
const [colorBy, setColorBy] = useURLState('color_by');
|
|
349
250
|
const {isDarkMode} = useParcaContext();
|
|
350
251
|
const [expanded, setExpanded] = useState<ExpandedState>({});
|
|
351
252
|
const [scrollToIndex, setScrollToIndex] = useState<number | undefined>(undefined);
|
|
352
253
|
|
|
353
254
|
const {compareMode} = useProfileViewContext();
|
|
354
255
|
|
|
355
|
-
const
|
|
356
|
-
if (
|
|
357
|
-
return
|
|
256
|
+
const table = useMemo(() => {
|
|
257
|
+
if (loading || data == null) {
|
|
258
|
+
return null;
|
|
358
259
|
}
|
|
359
260
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
};
|
|
261
|
+
return tableFromIPC(data);
|
|
262
|
+
}, [data, loading]);
|
|
363
263
|
|
|
364
|
-
const
|
|
365
|
-
|
|
366
|
-
|
|
264
|
+
const mappingsList = useMappingList(metadataMappingFiles);
|
|
265
|
+
const filenamesList = useFilenamesList(table);
|
|
266
|
+
const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : (colorBy as string);
|
|
267
|
+
|
|
268
|
+
const mappingsListCount = useMemo(
|
|
269
|
+
() => mappingsList.filter(m => m !== '').length,
|
|
270
|
+
[mappingsList]
|
|
271
|
+
);
|
|
272
|
+
|
|
273
|
+
// If there is only one mapping file, we want to color by filename by default.
|
|
274
|
+
useEffect(() => {
|
|
275
|
+
if (mappingsListCount === 1 && colorBy !== 'filename') {
|
|
276
|
+
setColorBy('filename');
|
|
367
277
|
}
|
|
278
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
279
|
+
}, [mappingsListCount]);
|
|
280
|
+
|
|
281
|
+
const filenameColors = useMemo(() => {
|
|
282
|
+
const colors = getFilenameColors(filenamesList, isDarkMode, currentColorProfile);
|
|
283
|
+
return colors;
|
|
284
|
+
}, [isDarkMode, filenamesList, currentColorProfile]);
|
|
368
285
|
|
|
369
|
-
|
|
286
|
+
const mappingColors = useMemo(() => {
|
|
287
|
+
const colors = getMappingColors(mappingsList, isDarkMode, currentColorProfile);
|
|
288
|
+
return colors;
|
|
289
|
+
}, [isDarkMode, mappingsList, currentColorProfile]);
|
|
290
|
+
|
|
291
|
+
const colorByList = {
|
|
292
|
+
filename: filenameColors,
|
|
293
|
+
binary: mappingColors,
|
|
370
294
|
};
|
|
371
295
|
|
|
296
|
+
type ColorByKey = keyof typeof colorByList;
|
|
297
|
+
|
|
298
|
+
const colorByColors: colorByColors = colorByList[colorByValue as ColorByKey];
|
|
299
|
+
|
|
372
300
|
const columnHelper = createColumnHelper<Row>();
|
|
373
301
|
|
|
374
302
|
unit = useMemo(() => unit ?? profileType?.sampleUnit ?? '', [unit, profileType?.sampleUnit]);
|
|
375
303
|
|
|
376
304
|
const columns = useMemo<Array<ColumnDef<Row>>>(() => {
|
|
377
305
|
return [
|
|
306
|
+
columnHelper.accessor('color', {
|
|
307
|
+
id: 'color',
|
|
308
|
+
header: '',
|
|
309
|
+
cell: info => {
|
|
310
|
+
const color = info.getValue() as string;
|
|
311
|
+
return <div className="w-4 h-4 rounded-[4px]" style={{backgroundColor: color}} />;
|
|
312
|
+
},
|
|
313
|
+
size: 10,
|
|
314
|
+
}),
|
|
378
315
|
columnHelper.accessor('flat', {
|
|
379
316
|
id: 'flat',
|
|
380
317
|
header: 'Flat',
|
|
@@ -392,7 +329,7 @@ export const Table = React.memo(function Table({
|
|
|
392
329
|
if (isDummyRow(info.row.original)) {
|
|
393
330
|
return '';
|
|
394
331
|
}
|
|
395
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue());
|
|
332
|
+
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
396
333
|
},
|
|
397
334
|
size: 120,
|
|
398
335
|
meta: {
|
|
@@ -418,7 +355,7 @@ export const Table = React.memo(function Table({
|
|
|
418
355
|
if (isDummyRow(info.row.original)) {
|
|
419
356
|
return '';
|
|
420
357
|
}
|
|
421
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue());
|
|
358
|
+
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
422
359
|
},
|
|
423
360
|
size: 120,
|
|
424
361
|
meta: {
|
|
@@ -443,7 +380,7 @@ export const Table = React.memo(function Table({
|
|
|
443
380
|
if (isDummyRow(info.row.original)) {
|
|
444
381
|
return '';
|
|
445
382
|
}
|
|
446
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue());
|
|
383
|
+
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
447
384
|
},
|
|
448
385
|
size: 150,
|
|
449
386
|
meta: {
|
|
@@ -469,7 +406,7 @@ export const Table = React.memo(function Table({
|
|
|
469
406
|
if (isDummyRow(info.row.original)) {
|
|
470
407
|
return '';
|
|
471
408
|
}
|
|
472
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue());
|
|
409
|
+
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
473
410
|
},
|
|
474
411
|
size: 170,
|
|
475
412
|
meta: {
|
|
@@ -503,6 +440,7 @@ export const Table = React.memo(function Table({
|
|
|
503
440
|
|
|
504
441
|
const [columnVisibility, setColumnVisibility] = useState(() => {
|
|
505
442
|
return {
|
|
443
|
+
color: true,
|
|
506
444
|
flat: true,
|
|
507
445
|
flatPercentage: false,
|
|
508
446
|
flatDiff: compareMode,
|
|
@@ -552,37 +490,40 @@ export const Table = React.memo(function Table({
|
|
|
552
490
|
[selectSpan, dashboardItems.length]
|
|
553
491
|
);
|
|
554
492
|
|
|
555
|
-
const onRowDoubleClick = useCallback(
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
row.
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
493
|
+
const onRowDoubleClick = useCallback(
|
|
494
|
+
(row: RowType<Row>, rows: Array<RowType<Row>>) => {
|
|
495
|
+
if (isDummyRow(row.original)) {
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
if (!isSubRow(row.original)) {
|
|
499
|
+
row.toggleExpanded();
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
// find the original row for this subrow and toggle it
|
|
503
|
+
const newRow = rows.find(
|
|
504
|
+
r =>
|
|
505
|
+
!isDummyRow(r.original) &&
|
|
506
|
+
!isDummyRow(row.original) &&
|
|
507
|
+
r.original.name === row.original.name &&
|
|
508
|
+
!isSubRow(r.original)
|
|
509
|
+
);
|
|
510
|
+
const parentRow = rows.find(r => {
|
|
511
|
+
const parent = row.getParentRow()!;
|
|
512
|
+
if (isDummyRow(parent.original) || isDummyRow(r.original)) {
|
|
513
|
+
return false;
|
|
514
|
+
}
|
|
515
|
+
return r.original.name === parent.original.name;
|
|
516
|
+
});
|
|
517
|
+
if (parentRow == null || newRow == null) {
|
|
518
|
+
return;
|
|
575
519
|
}
|
|
576
|
-
return r.original.name === parent.original.name;
|
|
577
|
-
});
|
|
578
|
-
if (parentRow == null || newRow == null) {
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
520
|
|
|
582
|
-
|
|
521
|
+
newRow.toggleExpanded();
|
|
583
522
|
|
|
584
|
-
|
|
585
|
-
|
|
523
|
+
setScrollToIndex(getScrollTargetIndex(rows, parentRow, newRow));
|
|
524
|
+
},
|
|
525
|
+
[setScrollToIndex]
|
|
526
|
+
);
|
|
586
527
|
|
|
587
528
|
const shouldHighlightRow = useCallback(
|
|
588
529
|
(row: Row) => {
|
|
@@ -608,14 +549,6 @@ export const Table = React.memo(function Table({
|
|
|
608
549
|
];
|
|
609
550
|
}, [compareMode]);
|
|
610
551
|
|
|
611
|
-
const table = useMemo(() => {
|
|
612
|
-
if (loading || data == null) {
|
|
613
|
-
return null;
|
|
614
|
-
}
|
|
615
|
-
|
|
616
|
-
return tableFromIPC(data);
|
|
617
|
-
}, [data, loading]);
|
|
618
|
-
|
|
619
552
|
const rows: DataRow[] = useMemo(() => {
|
|
620
553
|
if (table == null || table.numRows === 0) {
|
|
621
554
|
return [];
|
|
@@ -644,6 +577,13 @@ export const Table = React.memo(function Table({
|
|
|
644
577
|
|
|
645
578
|
return {
|
|
646
579
|
id: i,
|
|
580
|
+
color: getRowColor(
|
|
581
|
+
colorByColors,
|
|
582
|
+
mappingFileColumn,
|
|
583
|
+
i,
|
|
584
|
+
functionFileNameColumn,
|
|
585
|
+
colorBy as string
|
|
586
|
+
),
|
|
647
587
|
name: RowName(mappingFileColumn, locationAddressColumn, functionNameColumn, i),
|
|
648
588
|
flat,
|
|
649
589
|
flatDiff,
|
|
@@ -676,7 +616,21 @@ export const Table = React.memo(function Table({
|
|
|
676
616
|
}
|
|
677
617
|
|
|
678
618
|
return rows;
|
|
679
|
-
}, [table]);
|
|
619
|
+
}, [table, colorByColors, colorBy]);
|
|
620
|
+
|
|
621
|
+
useEffect(() => {
|
|
622
|
+
setTimeout(() => {
|
|
623
|
+
if (currentSearchString == null || rows.length === 0) return;
|
|
624
|
+
|
|
625
|
+
const firstHighlightedRowIndex = rows.findIndex(row => {
|
|
626
|
+
return !isDummyRow(row) && isSearchMatch(currentSearchString, row.name);
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
if (firstHighlightedRowIndex !== -1) {
|
|
630
|
+
setScrollToIndex(firstHighlightedRowIndex);
|
|
631
|
+
}
|
|
632
|
+
}, 1000); // Adding a delay to allow the table to render seems to be the only way to get this to work i.e. scrolling down to the highlighted row
|
|
633
|
+
}, [currentSearchString, rows]);
|
|
680
634
|
|
|
681
635
|
if (loading) {
|
|
682
636
|
return (
|
|
@@ -734,85 +688,4 @@ export const Table = React.memo(function Table({
|
|
|
734
688
|
);
|
|
735
689
|
});
|
|
736
690
|
|
|
737
|
-
export const addPlusSign = (num: string): string => {
|
|
738
|
-
if (num.charAt(0) === '0' || num.charAt(0) === '-') {
|
|
739
|
-
return num;
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
return `+${num}`;
|
|
743
|
-
};
|
|
744
|
-
|
|
745
|
-
export const RowName = (
|
|
746
|
-
mappingFileColumn: Vector | null,
|
|
747
|
-
locationAddressColumn: Vector | null,
|
|
748
|
-
functionNameColumn: Vector | null,
|
|
749
|
-
row: number
|
|
750
|
-
): string => {
|
|
751
|
-
if (mappingFileColumn === null) {
|
|
752
|
-
console.error('mapping_file column not found');
|
|
753
|
-
return '';
|
|
754
|
-
}
|
|
755
|
-
|
|
756
|
-
const mappingFile: string | null = mappingFileColumn?.get(row);
|
|
757
|
-
let mapping = '';
|
|
758
|
-
// Show the last item in the mapping file only if there are more than 1 mappings
|
|
759
|
-
if (mappingFile != null && mappingFileColumn.data.length > 1) {
|
|
760
|
-
mapping = `[${getLastItem(mappingFile) ?? ''}]`;
|
|
761
|
-
}
|
|
762
|
-
const functionName: string | null = functionNameColumn?.get(row) ?? '';
|
|
763
|
-
if (functionName !== null && functionName !== '') {
|
|
764
|
-
return `${mapping} ${functionName}`;
|
|
765
|
-
}
|
|
766
|
-
|
|
767
|
-
const address: bigint = locationAddressColumn?.get(row) ?? 0;
|
|
768
|
-
|
|
769
|
-
return hexifyAddress(address);
|
|
770
|
-
};
|
|
771
|
-
|
|
772
|
-
const getRowsCount = (rows: Array<RowType<Row>>): number => {
|
|
773
|
-
if (rows.length < 6) {
|
|
774
|
-
return 6;
|
|
775
|
-
}
|
|
776
|
-
|
|
777
|
-
return rows.length;
|
|
778
|
-
};
|
|
779
|
-
|
|
780
|
-
function getScrollTargetIndex(
|
|
781
|
-
rows: Array<RowType<Row>>,
|
|
782
|
-
parentRow: RowType<Row>,
|
|
783
|
-
newRow: RowType<Row>
|
|
784
|
-
): number {
|
|
785
|
-
const parentIndex = rows.indexOf(parentRow);
|
|
786
|
-
const newRowIndex = rows.indexOf(newRow);
|
|
787
|
-
let targetIndex = newRowIndex;
|
|
788
|
-
if (parentIndex > newRowIndex) {
|
|
789
|
-
// Adjusting the number of subs rows to scroll to the main row after expansion.
|
|
790
|
-
targetIndex -= getRowsCount(newRow.subRows);
|
|
791
|
-
}
|
|
792
|
-
if (parentIndex < newRowIndex) {
|
|
793
|
-
// If the parent row is above the new row, we need to adjust the number of subrows of the parent.
|
|
794
|
-
targetIndex += getRowsCount(parentRow.subRows);
|
|
795
|
-
}
|
|
796
|
-
if (targetIndex < 0) {
|
|
797
|
-
targetIndex = 0;
|
|
798
|
-
}
|
|
799
|
-
return targetIndex;
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
function isSubRow(row: Row): boolean {
|
|
803
|
-
return row.isTopSubRow === true || row.isBottomSubRow === true;
|
|
804
|
-
}
|
|
805
|
-
|
|
806
|
-
function isLastSubRow(row: RowType<Row>, rows: Array<RowType<Row>>): boolean {
|
|
807
|
-
const index = rows.indexOf(row);
|
|
808
|
-
const nextRow = rows[index + 1];
|
|
809
|
-
return nextRow == null || (!isSubRow(nextRow.original) && !nextRow.getIsExpanded());
|
|
810
|
-
}
|
|
811
|
-
|
|
812
|
-
function isFirstSubRow(row: RowType<Row>, rows: Array<RowType<Row>>): boolean {
|
|
813
|
-
const index = rows.indexOf(row);
|
|
814
|
-
const prevRow = rows[index - 1];
|
|
815
|
-
return prevRow == null || (!isSubRow(prevRow.original) && !prevRow.getIsExpanded());
|
|
816
|
-
}
|
|
817
|
-
|
|
818
691
|
export default Table;
|