@parca/profile 0.18.4 → 0.19.1
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 +10 -0
- package/dist/GraphTooltipArrow/useGraphTooltip/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/useGraphTooltip/index.js +6 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +2 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +13 -3
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts +1 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts +4 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +15 -6
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.js +5 -4
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts +2 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.js +3 -2
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +3 -0
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +4 -4
- package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +1 -1
- package/dist/ProfileIcicleGraph/index.d.ts +4 -1
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +22 -6
- package/dist/ProfileSelector/QueryControls.d.ts.map +1 -1
- package/dist/ProfileSelector/QueryControls.js +1 -1
- package/dist/ProfileView/components/DashboardItems/index.d.ts +3 -1
- package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
- package/dist/ProfileView/components/DashboardItems/index.js +4 -1
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +0 -13
- package/dist/ProfileView/components/Toolbars/index.d.ts +8 -0
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +6 -2
- package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts +1 -0
- package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/Dropdown.js +1 -1
- package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/index.js +9 -0
- package/dist/ProfileView/hooks/useVisualizationState.d.ts +4 -0
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +9 -1
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +3 -2
- package/dist/ProfileView/types/visualization.d.ts +1 -1
- package/dist/ProfileView/types/visualization.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +1 -1
- package/dist/Sandwich/components/CalleesSection.d.ts +25 -0
- package/dist/Sandwich/components/CalleesSection.d.ts.map +1 -0
- package/dist/Sandwich/components/CalleesSection.js +11 -0
- package/dist/Sandwich/components/CallersSection.d.ts +25 -0
- package/dist/Sandwich/components/CallersSection.d.ts.map +1 -0
- package/dist/Sandwich/components/CallersSection.js +11 -0
- package/dist/Sandwich/components/TableSection.d.ts +21 -0
- package/dist/Sandwich/components/TableSection.d.ts.map +1 -0
- package/dist/Sandwich/components/TableSection.js +7 -0
- package/dist/Sandwich/index.d.ts +19 -0
- package/dist/Sandwich/index.d.ts.map +1 -0
- package/dist/Sandwich/index.js +182 -0
- package/dist/Sandwich/utils/processRowData.d.ts +11 -0
- package/dist/Sandwich/utils/processRowData.d.ts.map +1 -0
- package/dist/Sandwich/utils/processRowData.js +53 -0
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +18 -4
- package/dist/Table/ColorCell.d.ts +7 -0
- package/dist/Table/ColorCell.d.ts.map +1 -0
- package/dist/Table/ColorCell.js +2 -0
- package/dist/Table/MoreDropdown.d.ts +5 -0
- package/dist/Table/MoreDropdown.d.ts.map +1 -0
- package/dist/Table/MoreDropdown.js +39 -0
- package/dist/Table/hooks/useColorManagement.d.ts +14 -0
- package/dist/Table/hooks/useColorManagement.d.ts.map +1 -0
- package/dist/Table/hooks/useColorManagement.js +32 -0
- package/dist/Table/hooks/useTableConfiguration.d.ts +21 -0
- package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -0
- package/dist/Table/hooks/useTableConfiguration.js +204 -0
- package/dist/Table/index.d.ts +14 -4
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +34 -332
- package/dist/Table/utils/functions.d.ts +1 -0
- package/dist/Table/utils/functions.d.ts.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/useQuery.d.ts +1 -0
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +7 -1
- package/package.json +7 -7
- package/src/GraphTooltipArrow/useGraphTooltip/index.ts +6 -3
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +23 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenuWrapper.tsx +1 -0
- package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +34 -5
- package/src/ProfileIcicleGraph/IcicleGraphArrow/MemoizedTooltip.tsx +6 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/TooltipContext.tsx +5 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +13 -1
- package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +1 -1
- package/src/ProfileIcicleGraph/index.tsx +50 -18
- package/src/ProfileSelector/QueryControls.tsx +1 -0
- package/src/ProfileView/components/DashboardItems/index.tsx +21 -0
- package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +11 -25
- package/src/ProfileView/components/Toolbars/index.tsx +42 -1
- package/src/ProfileView/components/ViewSelector/Dropdown.tsx +2 -1
- package/src/ProfileView/components/ViewSelector/index.tsx +11 -0
- package/src/ProfileView/hooks/useVisualizationState.ts +16 -1
- package/src/ProfileView/index.tsx +7 -0
- package/src/ProfileView/types/visualization.ts +7 -1
- package/src/ProfileViewWithData.tsx +1 -1
- package/src/Sandwich/components/CalleesSection.tsx +87 -0
- package/src/Sandwich/components/CallersSection.tsx +88 -0
- package/src/Sandwich/components/TableSection.tsx +67 -0
- package/src/Sandwich/index.tsx +342 -0
- package/src/Sandwich/utils/processRowData.ts +78 -0
- package/src/SimpleMatchers/index.tsx +20 -4
- package/src/Table/ColorCell.tsx +26 -0
- package/src/Table/MoreDropdown.tsx +75 -0
- package/src/Table/hooks/useColorManagement.ts +58 -0
- package/src/Table/hooks/useTableConfiguration.tsx +237 -0
- package/src/Table/index.tsx +37 -470
- package/src/Table/utils/functions.ts +1 -0
- package/src/useQuery.tsx +10 -1
package/src/Table/index.tsx
CHANGED
|
@@ -11,20 +11,10 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import React, {useCallback, useEffect, useMemo,
|
|
14
|
+
import React, {useCallback, useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
createColumnHelper,
|
|
19
|
-
type CellContext,
|
|
20
|
-
type ColumnDef,
|
|
21
|
-
type ExpandedState,
|
|
22
|
-
type Row as RowType,
|
|
23
|
-
} from '@tanstack/table-core';
|
|
24
|
-
import {Int64, Vector, tableFromIPC, vectorFromArray} from 'apache-arrow';
|
|
25
|
-
import cx from 'classnames';
|
|
16
|
+
import {tableFromIPC} from 'apache-arrow';
|
|
26
17
|
import {AnimatePresence, motion} from 'framer-motion';
|
|
27
|
-
import {Tooltip} from 'react-tooltip';
|
|
28
18
|
|
|
29
19
|
import {
|
|
30
20
|
Table as TableComponent,
|
|
@@ -32,60 +22,33 @@ import {
|
|
|
32
22
|
useParcaContext,
|
|
33
23
|
useURLState,
|
|
34
24
|
} from '@parca/components';
|
|
35
|
-
import {type RowRendererProps} from '@parca/components/dist/Table';
|
|
36
25
|
import {useCurrentColorProfile} from '@parca/hooks';
|
|
37
26
|
import {ProfileType} from '@parca/parser';
|
|
38
|
-
import {
|
|
27
|
+
import {isSearchMatch} from '@parca/utilities';
|
|
39
28
|
|
|
40
|
-
import {getFilenameColors, getMappingColors} from '../ProfileIcicleGraph/IcicleGraphArrow/';
|
|
41
|
-
import {colorByColors} from '../ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes';
|
|
42
29
|
import useMappingList, {
|
|
43
30
|
useFilenamesList,
|
|
44
31
|
} from '../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
|
|
45
32
|
import {useProfileViewContext} from '../ProfileView/context/ProfileViewContext';
|
|
46
|
-
import {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
} from './utils/functions';
|
|
66
|
-
import {getTopAndBottomExpandedRowModel} from './utils/topAndBottomExpandedRowModel';
|
|
67
|
-
|
|
68
|
-
const FIELD_MAPPING_FILE = 'mapping_file';
|
|
69
|
-
const FIELD_LOCATION_ADDRESS = 'location_address';
|
|
70
|
-
const FIELD_FUNCTION_NAME = 'function_name';
|
|
71
|
-
const FIELD_FUNCTION_SYSTEM_NAME = 'function_system_name';
|
|
72
|
-
const FIELD_FUNCTION_FILE_NAME = 'function_file_name';
|
|
73
|
-
const FIELD_FLAT = 'flat';
|
|
74
|
-
const FIELD_FLAT_DIFF = 'flat_diff';
|
|
75
|
-
const FIELD_CUMULATIVE = 'cumulative';
|
|
76
|
-
const FIELD_CUMULATIVE_DIFF = 'cumulative_diff';
|
|
77
|
-
const FIELD_CALLERS = 'callers';
|
|
78
|
-
const FIELD_CALLEES = 'callees';
|
|
79
|
-
|
|
80
|
-
export type Row = DataRow | DummyRow;
|
|
81
|
-
|
|
82
|
-
export const isDummyRow = (row: Row): row is DummyRow => {
|
|
83
|
-
return 'size' in row;
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
let doubleClickTimer: NodeJS.Timeout | null = null;
|
|
87
|
-
|
|
88
|
-
interface TableProps {
|
|
33
|
+
import {useColorManagement} from './hooks/useColorManagement';
|
|
34
|
+
import {useTableConfiguration} from './hooks/useTableConfiguration';
|
|
35
|
+
import {DataRow, ROW_HEIGHT, RowName, getRowColor} from './utils/functions';
|
|
36
|
+
|
|
37
|
+
export const FIELD_MAPPING_FILE = 'mapping_file';
|
|
38
|
+
export const FIELD_LOCATION_ADDRESS = 'location_address';
|
|
39
|
+
export const FIELD_FUNCTION_NAME = 'function_name';
|
|
40
|
+
export const FIELD_FUNCTION_SYSTEM_NAME = 'function_system_name';
|
|
41
|
+
export const FIELD_FUNCTION_FILE_NAME = 'function_file_name';
|
|
42
|
+
export const FIELD_FLAT = 'flat';
|
|
43
|
+
export const FIELD_FLAT_DIFF = 'flat_diff';
|
|
44
|
+
export const FIELD_CUMULATIVE = 'cumulative';
|
|
45
|
+
export const FIELD_CUMULATIVE_DIFF = 'cumulative_diff';
|
|
46
|
+
export const FIELD_CALLERS = 'callers';
|
|
47
|
+
export const FIELD_CALLEES = 'callees';
|
|
48
|
+
|
|
49
|
+
export type Row = DataRow;
|
|
50
|
+
|
|
51
|
+
export interface TableProps {
|
|
89
52
|
data?: Uint8Array;
|
|
90
53
|
total: bigint;
|
|
91
54
|
filtered: bigint;
|
|
@@ -99,134 +62,6 @@ interface TableProps {
|
|
|
99
62
|
metadataMappingFiles?: string[];
|
|
100
63
|
}
|
|
101
64
|
|
|
102
|
-
const CustomRowRenderer = ({
|
|
103
|
-
row,
|
|
104
|
-
usePointerCursor,
|
|
105
|
-
onRowClick,
|
|
106
|
-
onRowDoubleClick,
|
|
107
|
-
enableHighlighting,
|
|
108
|
-
shouldHighlightRow,
|
|
109
|
-
rows,
|
|
110
|
-
}: RowRendererProps<Row>): React.JSX.Element => {
|
|
111
|
-
const data = row.original;
|
|
112
|
-
const isExpanded = row.getIsExpanded();
|
|
113
|
-
const _isSubRow = isSubRow(data);
|
|
114
|
-
const _isLastSubRow = isLastSubRow(row, rows);
|
|
115
|
-
const _isFirstSubRow = isFirstSubRow(row, rows);
|
|
116
|
-
const bgClassNames = rowBgClassNames(isExpanded, _isSubRow);
|
|
117
|
-
const ref = useRef<HTMLTableRowElement>(null);
|
|
118
|
-
const [rowHeight, setRowHeight] = useState<number>(ROW_HEIGHT);
|
|
119
|
-
|
|
120
|
-
useEffect(() => {
|
|
121
|
-
if (ref.current != null) {
|
|
122
|
-
setRowHeight(ref.current.clientHeight + 1); // +1 to account for the bottom border
|
|
123
|
-
}
|
|
124
|
-
}, []);
|
|
125
|
-
|
|
126
|
-
const paddingElement = (
|
|
127
|
-
<div
|
|
128
|
-
className={cx(
|
|
129
|
-
'bg-white dark:bg-indigo-500 w-[18px] absolute top-[-1px] left-0 border-x border-gray-200 dark:border-gray-700',
|
|
130
|
-
{
|
|
131
|
-
'border-b': _isLastSubRow,
|
|
132
|
-
'border-t': _isFirstSubRow,
|
|
133
|
-
}
|
|
134
|
-
)}
|
|
135
|
-
style={{height: `${rowHeight}px`}}
|
|
136
|
-
/>
|
|
137
|
-
);
|
|
138
|
-
|
|
139
|
-
if (isDummyRow(data)) {
|
|
140
|
-
return (
|
|
141
|
-
<tr key={row.id} className={cx(bgClassNames)} ref={ref}>
|
|
142
|
-
{paddingElement}
|
|
143
|
-
<td colSpan={100} className={`text-center`} style={sizeToHeightStyle(data.size)}>
|
|
144
|
-
{data.message}
|
|
145
|
-
</td>
|
|
146
|
-
</tr>
|
|
147
|
-
);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return (
|
|
151
|
-
<tr
|
|
152
|
-
key={row.id}
|
|
153
|
-
ref={ref}
|
|
154
|
-
className={cx(usePointerCursor === true ? 'cursor-pointer' : 'cursor-auto', bgClassNames, {
|
|
155
|
-
'hover:bg-[#62626212] dark:hover:bg-[#ffffff12] ': !isExpanded && !_isSubRow,
|
|
156
|
-
'hover:bg-indigo-200 dark:hover:bg-indigo-500': isExpanded || _isSubRow,
|
|
157
|
-
})}
|
|
158
|
-
onClick={e => {
|
|
159
|
-
if (typeof onRowClick !== 'function') {
|
|
160
|
-
return;
|
|
161
|
-
}
|
|
162
|
-
if (e.detail === 2 && doubleClickTimer != null) {
|
|
163
|
-
// Prevent the click event from being triggered as it is part of a double click
|
|
164
|
-
clearTimeout(doubleClickTimer);
|
|
165
|
-
doubleClickTimer = null;
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
if (e.detail === 1) {
|
|
169
|
-
// Schedule a single click event to be triggered after 150ms
|
|
170
|
-
doubleClickTimer = setTimeout(() => {
|
|
171
|
-
doubleClickTimer = null;
|
|
172
|
-
onRowClick(row.original);
|
|
173
|
-
}, 150);
|
|
174
|
-
}
|
|
175
|
-
}}
|
|
176
|
-
onDoubleClick={
|
|
177
|
-
onRowDoubleClick != null
|
|
178
|
-
? () => {
|
|
179
|
-
onRowDoubleClick(row, rows);
|
|
180
|
-
window.getSelection()?.removeAllRanges();
|
|
181
|
-
}
|
|
182
|
-
: undefined
|
|
183
|
-
}
|
|
184
|
-
style={
|
|
185
|
-
enableHighlighting !== true || shouldHighlightRow === undefined
|
|
186
|
-
? undefined
|
|
187
|
-
: {opacity: shouldHighlightRow(row.original) ? 1 : 0.5}
|
|
188
|
-
}
|
|
189
|
-
>
|
|
190
|
-
{row.getVisibleCells().map((cell, idx) => {
|
|
191
|
-
return (
|
|
192
|
-
<td
|
|
193
|
-
key={cell.id}
|
|
194
|
-
className={cx('p-1.5 align-top relative', {
|
|
195
|
-
/* @ts-expect-error */
|
|
196
|
-
'text-right': cell.column.columnDef.meta?.align === 'right',
|
|
197
|
-
/* @ts-expect-error */
|
|
198
|
-
'text-left': cell.column.columnDef.meta?.align === 'left',
|
|
199
|
-
'pl-5 whitespace-nowrap': idx === 0,
|
|
200
|
-
})}
|
|
201
|
-
>
|
|
202
|
-
{idx === 0 && isExpanded ? (
|
|
203
|
-
<>
|
|
204
|
-
<div
|
|
205
|
-
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`}
|
|
206
|
-
style={{...sizeToWidthStyle(3)}}
|
|
207
|
-
>
|
|
208
|
-
Callers {'->'}
|
|
209
|
-
</div>
|
|
210
|
-
<div
|
|
211
|
-
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`}
|
|
212
|
-
style={{
|
|
213
|
-
...sizeToWidthStyle(3),
|
|
214
|
-
...sizeToBottomStyle(3),
|
|
215
|
-
}}
|
|
216
|
-
>
|
|
217
|
-
{'<-'} Callees
|
|
218
|
-
</div>
|
|
219
|
-
</>
|
|
220
|
-
) : null}
|
|
221
|
-
{idx === 0 && _isSubRow ? paddingElement : null}
|
|
222
|
-
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
|
223
|
-
</td>
|
|
224
|
-
);
|
|
225
|
-
})}
|
|
226
|
-
</tr>
|
|
227
|
-
);
|
|
228
|
-
};
|
|
229
|
-
|
|
230
65
|
export const Table = React.memo(function Table({
|
|
231
66
|
data,
|
|
232
67
|
total,
|
|
@@ -244,12 +79,8 @@ export const Table = React.memo(function Table({
|
|
|
244
79
|
alwaysReturnArray: true,
|
|
245
80
|
});
|
|
246
81
|
|
|
247
|
-
const [tableColumns] = useURLState<string[]>('table_columns', {
|
|
248
|
-
alwaysReturnArray: true,
|
|
249
|
-
});
|
|
250
82
|
const [colorBy, setColorBy] = useURLState('color_by');
|
|
251
83
|
const {isDarkMode} = useParcaContext();
|
|
252
|
-
const [expanded, setExpanded] = useState<ExpandedState>({});
|
|
253
84
|
const [scrollToIndex, setScrollToIndex] = useState<number | undefined>(undefined);
|
|
254
85
|
|
|
255
86
|
const {compareMode} = useProfileViewContext();
|
|
@@ -264,7 +95,6 @@ export const Table = React.memo(function Table({
|
|
|
264
95
|
|
|
265
96
|
const mappingsList = useMappingList(metadataMappingFiles);
|
|
266
97
|
const filenamesList = useFilenamesList(table);
|
|
267
|
-
const colorByValue = colorBy === undefined || colorBy === '' ? 'binary' : (colorBy as string);
|
|
268
98
|
|
|
269
99
|
const mappingsListCount = useMemo(
|
|
270
100
|
() => mappingsList.filter(m => m !== '').length,
|
|
@@ -279,205 +109,24 @@ export const Table = React.memo(function Table({
|
|
|
279
109
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
280
110
|
}, [mappingsListCount]);
|
|
281
111
|
|
|
282
|
-
const
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
return colors;
|
|
290
|
-
}, [isDarkMode, mappingsList, currentColorProfile]);
|
|
291
|
-
|
|
292
|
-
const colorByList = {
|
|
293
|
-
filename: filenameColors,
|
|
294
|
-
binary: mappingColors,
|
|
295
|
-
};
|
|
296
|
-
|
|
297
|
-
type ColorByKey = keyof typeof colorByList;
|
|
298
|
-
|
|
299
|
-
const colorByColors: colorByColors = colorByList[colorByValue as ColorByKey];
|
|
300
|
-
|
|
301
|
-
const columnHelper = createColumnHelper<Row>();
|
|
112
|
+
const {colorByColors} = useColorManagement({
|
|
113
|
+
isDarkMode,
|
|
114
|
+
currentColorProfile,
|
|
115
|
+
mappingsList,
|
|
116
|
+
filenamesList,
|
|
117
|
+
colorBy: colorBy as string,
|
|
118
|
+
});
|
|
302
119
|
|
|
303
120
|
unit = useMemo(() => unit ?? profileType?.sampleUnit ?? '', [unit, profileType?.sampleUnit]);
|
|
304
121
|
|
|
305
|
-
const
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
cell: info => {
|
|
311
|
-
const color = info.getValue() as {color: string; mappingFile: string};
|
|
312
|
-
return (
|
|
313
|
-
<>
|
|
314
|
-
<div
|
|
315
|
-
className="w-4 h-4 rounded-[4px]"
|
|
316
|
-
style={{backgroundColor: color.color}}
|
|
317
|
-
data-tooltip-id="table-color-tooltip"
|
|
318
|
-
data-tooltip-content={getLastItem(color.mappingFile)}
|
|
319
|
-
/>
|
|
320
|
-
<Tooltip id="table-color-tooltip" />
|
|
321
|
-
</>
|
|
322
|
-
);
|
|
323
|
-
},
|
|
324
|
-
size: 10,
|
|
325
|
-
}),
|
|
326
|
-
columnHelper.accessor('flat', {
|
|
327
|
-
id: 'flat',
|
|
328
|
-
header: 'Flat',
|
|
329
|
-
cell: info => valueFormatter((info as CellContext<DataRow, bigint>).getValue(), unit, 2),
|
|
330
|
-
size: 80,
|
|
331
|
-
meta: {
|
|
332
|
-
align: 'right',
|
|
333
|
-
},
|
|
334
|
-
invertSorting: true,
|
|
335
|
-
}),
|
|
336
|
-
columnHelper.accessor('flat', {
|
|
337
|
-
id: 'flatPercentage',
|
|
338
|
-
header: 'Flat (%)',
|
|
339
|
-
cell: info => {
|
|
340
|
-
if (isDummyRow(info.row.original)) {
|
|
341
|
-
return '';
|
|
342
|
-
}
|
|
343
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
344
|
-
},
|
|
345
|
-
size: 120,
|
|
346
|
-
meta: {
|
|
347
|
-
align: 'right',
|
|
348
|
-
},
|
|
349
|
-
invertSorting: true,
|
|
350
|
-
}),
|
|
351
|
-
columnHelper.accessor('flatDiff', {
|
|
352
|
-
id: 'flatDiff',
|
|
353
|
-
header: 'Flat Diff',
|
|
354
|
-
cell: info =>
|
|
355
|
-
addPlusSign(valueFormatter((info as CellContext<DataRow, bigint>).getValue(), unit, 2)),
|
|
356
|
-
size: 120,
|
|
357
|
-
meta: {
|
|
358
|
-
align: 'right',
|
|
359
|
-
},
|
|
360
|
-
invertSorting: true,
|
|
361
|
-
}),
|
|
362
|
-
columnHelper.accessor('flatDiff', {
|
|
363
|
-
id: 'flatDiffPercentage',
|
|
364
|
-
header: 'Flat Diff (%)',
|
|
365
|
-
cell: info => {
|
|
366
|
-
if (isDummyRow(info.row.original)) {
|
|
367
|
-
return '';
|
|
368
|
-
}
|
|
369
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
370
|
-
},
|
|
371
|
-
size: 120,
|
|
372
|
-
meta: {
|
|
373
|
-
align: 'right',
|
|
374
|
-
},
|
|
375
|
-
invertSorting: true,
|
|
376
|
-
}),
|
|
377
|
-
columnHelper.accessor('cumulative', {
|
|
378
|
-
id: 'cumulative',
|
|
379
|
-
header: 'Cumulative',
|
|
380
|
-
cell: info => valueFormatter((info as CellContext<DataRow, bigint>).getValue(), unit, 2),
|
|
381
|
-
size: 150,
|
|
382
|
-
meta: {
|
|
383
|
-
align: 'right',
|
|
384
|
-
},
|
|
385
|
-
invertSorting: true,
|
|
386
|
-
}),
|
|
387
|
-
columnHelper.accessor('cumulative', {
|
|
388
|
-
id: 'cumulativePercentage',
|
|
389
|
-
header: 'Cumulative (%)',
|
|
390
|
-
cell: info => {
|
|
391
|
-
if (isDummyRow(info.row.original)) {
|
|
392
|
-
return '';
|
|
393
|
-
}
|
|
394
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
395
|
-
},
|
|
396
|
-
size: 150,
|
|
397
|
-
meta: {
|
|
398
|
-
align: 'right',
|
|
399
|
-
},
|
|
400
|
-
invertSorting: true,
|
|
401
|
-
}),
|
|
402
|
-
columnHelper.accessor('cumulativeDiff', {
|
|
403
|
-
id: 'cumulativeDiff',
|
|
404
|
-
header: 'Cumulative Diff',
|
|
405
|
-
cell: info =>
|
|
406
|
-
addPlusSign(valueFormatter((info as CellContext<DataRow, bigint>).getValue(), unit, 2)),
|
|
407
|
-
size: 170,
|
|
408
|
-
meta: {
|
|
409
|
-
align: 'right',
|
|
410
|
-
},
|
|
411
|
-
invertSorting: true,
|
|
412
|
-
}),
|
|
413
|
-
columnHelper.accessor('cumulativeDiff', {
|
|
414
|
-
id: 'cumulativeDiffPercentage',
|
|
415
|
-
header: 'Cumulative Diff (%)',
|
|
416
|
-
cell: info => {
|
|
417
|
-
if (isDummyRow(info.row.original)) {
|
|
418
|
-
return '';
|
|
419
|
-
}
|
|
420
|
-
return ratioString((info as CellContext<DataRow, bigint>).getValue(), total, filtered);
|
|
421
|
-
},
|
|
422
|
-
size: 170,
|
|
423
|
-
meta: {
|
|
424
|
-
align: 'right',
|
|
425
|
-
},
|
|
426
|
-
invertSorting: true,
|
|
427
|
-
}),
|
|
428
|
-
columnHelper.accessor('name', {
|
|
429
|
-
id: 'name',
|
|
430
|
-
header: 'Name',
|
|
431
|
-
cell: info => info.getValue(),
|
|
432
|
-
}),
|
|
433
|
-
columnHelper.accessor('functionSystemName', {
|
|
434
|
-
id: 'functionSystemName',
|
|
435
|
-
header: 'Function System Name',
|
|
436
|
-
cell: info => info.getValue(),
|
|
437
|
-
}),
|
|
438
|
-
columnHelper.accessor('functionFileName', {
|
|
439
|
-
id: 'functionFileName',
|
|
440
|
-
header: 'Function File Name',
|
|
441
|
-
cell: info => info.getValue(),
|
|
442
|
-
}),
|
|
443
|
-
columnHelper.accessor('mappingFile', {
|
|
444
|
-
id: 'mappingFile',
|
|
445
|
-
header: 'Mapping File',
|
|
446
|
-
cell: info => info.getValue(),
|
|
447
|
-
}),
|
|
448
|
-
];
|
|
449
|
-
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
450
|
-
}, [profileType, unit]);
|
|
451
|
-
|
|
452
|
-
const [columnVisibility, setColumnVisibility] = useState(() => {
|
|
453
|
-
return {
|
|
454
|
-
color: true,
|
|
455
|
-
flat: true,
|
|
456
|
-
flatPercentage: false,
|
|
457
|
-
flatDiff: compareMode,
|
|
458
|
-
flatDiffPercentage: false,
|
|
459
|
-
cumulative: true,
|
|
460
|
-
cumulativePercentage: false,
|
|
461
|
-
cumulativeDiff: compareMode,
|
|
462
|
-
cumulativeDiffPercentage: false,
|
|
463
|
-
name: true,
|
|
464
|
-
functionSystemName: false,
|
|
465
|
-
functionFileName: false,
|
|
466
|
-
mappingFile: false,
|
|
467
|
-
};
|
|
122
|
+
const tableConfig = useTableConfiguration({
|
|
123
|
+
unit,
|
|
124
|
+
total,
|
|
125
|
+
filtered,
|
|
126
|
+
compareMode,
|
|
468
127
|
});
|
|
469
128
|
|
|
470
|
-
|
|
471
|
-
if (Array.isArray(tableColumns)) {
|
|
472
|
-
setColumnVisibility(prevState => {
|
|
473
|
-
const newState = {...prevState};
|
|
474
|
-
(Object.keys(newState) as ColumnName[]).forEach(column => {
|
|
475
|
-
newState[column] = tableColumns.includes(column);
|
|
476
|
-
});
|
|
477
|
-
return newState;
|
|
478
|
-
});
|
|
479
|
-
}
|
|
480
|
-
}, [tableColumns]);
|
|
129
|
+
const {columns, initialSorting, columnVisibility} = tableConfig;
|
|
481
130
|
|
|
482
131
|
const selectSpan = useCallback(
|
|
483
132
|
(span: string): void => {
|
|
@@ -488,10 +137,6 @@ export const Table = React.memo(function Table({
|
|
|
488
137
|
|
|
489
138
|
const onRowClick = useCallback(
|
|
490
139
|
(row: Row) => {
|
|
491
|
-
if (isDummyRow(row)) {
|
|
492
|
-
return;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
140
|
// If there is only one dashboard item, we don't want to select a span
|
|
496
141
|
if (dashboardItems.length <= 1) {
|
|
497
142
|
return;
|
|
@@ -501,41 +146,6 @@ export const Table = React.memo(function Table({
|
|
|
501
146
|
[selectSpan, dashboardItems.length]
|
|
502
147
|
);
|
|
503
148
|
|
|
504
|
-
const onRowDoubleClick = useCallback(
|
|
505
|
-
(row: RowType<Row>, rows: Array<RowType<Row>>) => {
|
|
506
|
-
if (isDummyRow(row.original)) {
|
|
507
|
-
return;
|
|
508
|
-
}
|
|
509
|
-
if (!isSubRow(row.original)) {
|
|
510
|
-
row.toggleExpanded();
|
|
511
|
-
return;
|
|
512
|
-
}
|
|
513
|
-
// find the original row for this subrow and toggle it
|
|
514
|
-
const newRow = rows.find(
|
|
515
|
-
r =>
|
|
516
|
-
!isDummyRow(r.original) &&
|
|
517
|
-
!isDummyRow(row.original) &&
|
|
518
|
-
r.original.name === row.original.name &&
|
|
519
|
-
!isSubRow(r.original)
|
|
520
|
-
);
|
|
521
|
-
const parentRow = rows.find(r => {
|
|
522
|
-
const parent = row.getParentRow()!;
|
|
523
|
-
if (isDummyRow(parent.original) || isDummyRow(r.original)) {
|
|
524
|
-
return false;
|
|
525
|
-
}
|
|
526
|
-
return r.original.name === parent.original.name;
|
|
527
|
-
});
|
|
528
|
-
if (parentRow == null || newRow == null) {
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
newRow.toggleExpanded();
|
|
533
|
-
|
|
534
|
-
setScrollToIndex(getScrollTargetIndex(rows, parentRow, newRow));
|
|
535
|
-
},
|
|
536
|
-
[setScrollToIndex]
|
|
537
|
-
);
|
|
538
|
-
|
|
539
149
|
const shouldHighlightRow = useCallback(
|
|
540
150
|
(row: Row) => {
|
|
541
151
|
if (!('name' in row)) {
|
|
@@ -551,15 +161,6 @@ export const Table = React.memo(function Table({
|
|
|
551
161
|
return currentSearchString != null && currentSearchString?.length > 0;
|
|
552
162
|
}, [currentSearchString]);
|
|
553
163
|
|
|
554
|
-
const initialSorting = useMemo(() => {
|
|
555
|
-
return [
|
|
556
|
-
{
|
|
557
|
-
id: compareMode ? 'flatDiff' : 'flat',
|
|
558
|
-
desc: false, // columns sorting are inverted - so this is actually descending
|
|
559
|
-
},
|
|
560
|
-
];
|
|
561
|
-
}, [compareMode]);
|
|
562
|
-
|
|
563
164
|
const rows: DataRow[] = useMemo(() => {
|
|
564
165
|
if (table == null || table.numRows === 0) {
|
|
565
166
|
return [];
|
|
@@ -574,8 +175,6 @@ export const Table = React.memo(function Table({
|
|
|
574
175
|
const functionFileNameColumn = table.getChild(FIELD_FUNCTION_FILE_NAME);
|
|
575
176
|
const mappingFileColumn = table.getChild(FIELD_MAPPING_FILE);
|
|
576
177
|
const locationAddressColumn = table.getChild(FIELD_LOCATION_ADDRESS);
|
|
577
|
-
const callersColumn = table.getChild(FIELD_CALLERS);
|
|
578
|
-
const calleesColumn = table.getChild(FIELD_CALLEES);
|
|
579
178
|
|
|
580
179
|
const getRow = (i: number): DataRow => {
|
|
581
180
|
const flat: bigint = flatColumn?.get(i) ?? 0n;
|
|
@@ -609,25 +208,7 @@ export const Table = React.memo(function Table({
|
|
|
609
208
|
};
|
|
610
209
|
};
|
|
611
210
|
|
|
612
|
-
const rows: DataRow[] =
|
|
613
|
-
for (let i = 0; i < table.numRows; i++) {
|
|
614
|
-
const row = getRow(i);
|
|
615
|
-
const callerIndices: Vector<Int64> = callersColumn?.get(i) ?? vectorFromArray([]);
|
|
616
|
-
const callers: DataRow[] = Array.from(callerIndices.toArray().values()).map(rowIdx => {
|
|
617
|
-
return getRow(Number(rowIdx));
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
const calleeIndices: Vector<Int64> = calleesColumn?.get(i) ?? vectorFromArray([]);
|
|
621
|
-
const callees: DataRow[] = Array.from(calleeIndices.toArray().values()).map(rowIdx => {
|
|
622
|
-
return getRow(Number(rowIdx));
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
row.callers = callers;
|
|
626
|
-
row.callees = callees;
|
|
627
|
-
row.subRows = [...getCallerRows(callers), ...getCalleeRows(callees)];
|
|
628
|
-
|
|
629
|
-
rows.push(row);
|
|
630
|
-
}
|
|
211
|
+
const rows: DataRow[] = Array.from({length: table.numRows}, (_, i) => getRow(i));
|
|
631
212
|
|
|
632
213
|
return rows;
|
|
633
214
|
}, [table, colorByColors, colorBy]);
|
|
@@ -637,7 +218,7 @@ export const Table = React.memo(function Table({
|
|
|
637
218
|
if (currentSearchString == null || rows.length === 0) return;
|
|
638
219
|
|
|
639
220
|
const firstHighlightedRowIndex = rows.findIndex(row => {
|
|
640
|
-
return
|
|
221
|
+
return isSearchMatch(currentSearchString, row.name);
|
|
641
222
|
});
|
|
642
223
|
|
|
643
224
|
if (firstHighlightedRowIndex !== -1) {
|
|
@@ -678,20 +259,6 @@ export const Table = React.memo(function Table({
|
|
|
678
259
|
enableHighlighting={enableHighlighting}
|
|
679
260
|
shouldHighlightRow={shouldHighlightRow}
|
|
680
261
|
usePointerCursor={dashboardItems.length > 1}
|
|
681
|
-
onRowDoubleClick={onRowDoubleClick}
|
|
682
|
-
getSubRows={row => (isDummyRow(row) ? [] : row.subRows ?? [])}
|
|
683
|
-
getCustomExpandedRowModel={getTopAndBottomExpandedRowModel}
|
|
684
|
-
expandedState={expanded}
|
|
685
|
-
onExpandedChange={getNewState => {
|
|
686
|
-
// We only want the new expanded row so passing the exisitng state as empty
|
|
687
|
-
// @ts-expect-error
|
|
688
|
-
let newState = getNewState({});
|
|
689
|
-
if (Object.keys(newState)[0] === Object.keys(expanded)[0]) {
|
|
690
|
-
newState = {};
|
|
691
|
-
}
|
|
692
|
-
setExpanded(newState);
|
|
693
|
-
}}
|
|
694
|
-
CustomRowRenderer={CustomRowRenderer}
|
|
695
262
|
scrollToIndex={scrollToIndex}
|
|
696
263
|
estimatedRowHeight={ROW_HEIGHT}
|
|
697
264
|
/>
|
package/src/useQuery.tsx
CHANGED
|
@@ -34,6 +34,7 @@ interface UseQueryOptions {
|
|
|
34
34
|
sourceOnly?: boolean;
|
|
35
35
|
invertCallStack?: boolean;
|
|
36
36
|
binaryFrameFilter?: string[];
|
|
37
|
+
sandwichByFunction?: string;
|
|
37
38
|
}
|
|
38
39
|
|
|
39
40
|
export const useQuery = (
|
|
@@ -57,6 +58,7 @@ export const useQuery = (
|
|
|
57
58
|
options?.invertCallStack ?? false,
|
|
58
59
|
options?.binaryFrameFilter ?? '',
|
|
59
60
|
profileSource.excludeFunction ?? false,
|
|
61
|
+
options?.sandwichByFunction ?? '',
|
|
60
62
|
],
|
|
61
63
|
queryFn: async () => {
|
|
62
64
|
const req = profileSource.QueryRequest();
|
|
@@ -73,8 +75,10 @@ export const useQuery = (
|
|
|
73
75
|
};
|
|
74
76
|
}
|
|
75
77
|
req.invertCallStack = options?.invertCallStack ?? false;
|
|
78
|
+
|
|
79
|
+
// Handle filter from ProfileSource (filter by function toolbar)
|
|
76
80
|
const functionToFilter = req.filterQuery;
|
|
77
|
-
if (functionToFilter !== undefined) {
|
|
81
|
+
if (functionToFilter !== undefined && functionToFilter !== '') {
|
|
78
82
|
req.filter = [
|
|
79
83
|
...req.filter,
|
|
80
84
|
{
|
|
@@ -94,6 +98,11 @@ export const useQuery = (
|
|
|
94
98
|
];
|
|
95
99
|
}
|
|
96
100
|
|
|
101
|
+
// Handle sandwich view filter separately
|
|
102
|
+
if (options?.sandwichByFunction !== undefined) {
|
|
103
|
+
req.sandwichByFunction = options.sandwichByFunction;
|
|
104
|
+
}
|
|
105
|
+
|
|
97
106
|
if (options?.binaryFrameFilter !== undefined && options?.binaryFrameFilter.length > 0) {
|
|
98
107
|
req.filter = [
|
|
99
108
|
...req.filter,
|