@parca/profile 0.19.19 → 0.19.21
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/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +1 -3
- package/dist/ProfileExplorer/index.d.ts.map +1 -1
- package/dist/ProfileExplorer/index.js +5 -8
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +0 -2
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts +0 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +2 -11
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +6 -14
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
- package/dist/ProfileSelector/useAutoQuerySelector.js +1 -1
- package/dist/ProfileSource.d.ts +4 -11
- package/dist/ProfileSource.d.ts.map +1 -1
- package/dist/ProfileSource.js +6 -14
- package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileView/components/ColorStackLegend.js +14 -10
- package/dist/ProfileView/components/DashboardItems/index.d.ts +1 -3
- package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
- package/dist/ProfileView/components/DashboardItems/index.js +2 -2
- package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts.map +1 -1
- package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +14 -1
- package/dist/ProfileView/components/InvertCallStack/index.js +1 -1
- package/dist/ProfileView/components/ProfileFilters/index.d.ts +5 -0
- package/dist/ProfileView/components/ProfileFilters/index.d.ts.map +1 -0
- package/dist/ProfileView/components/ProfileFilters/index.js +173 -0
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts +17 -0
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts.map +1 -0
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +209 -0
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +8 -0
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -0
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +87 -0
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +21 -11
- package/dist/ProfileView/components/Toolbars/index.d.ts +0 -5
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +6 -6
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +3 -12
- package/dist/ProfileView/hooks/useVisualizationState.d.ts +0 -3
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +0 -7
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +3 -5
- package/dist/ProfileViewWithData.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +8 -7
- package/dist/Sandwich/index.d.ts.map +1 -1
- package/dist/Sandwich/index.js +4 -2
- package/dist/Table/index.d.ts +0 -2
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +5 -32
- package/dist/styles.css +1 -1
- package/dist/useQuery.d.ts +1 -1
- package/dist/useQuery.d.ts.map +1 -1
- package/dist/useQuery.js +7 -40
- package/package.json +7 -7
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +0 -4
- package/src/ProfileExplorer/index.tsx +4 -13
- package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +0 -2
- package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +1 -14
- package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +4 -16
- package/src/ProfileSelector/useAutoQuerySelector.ts +1 -2
- package/src/ProfileSource.tsx +6 -49
- package/src/ProfileView/components/ColorStackLegend.tsx +16 -12
- package/src/ProfileView/components/DashboardItems/index.tsx +0 -6
- package/src/ProfileView/components/GroupByLabelsDropdown/index.tsx +15 -2
- package/src/ProfileView/components/InvertCallStack/index.tsx +1 -1
- package/src/ProfileView/components/ProfileFilters/index.tsx +294 -0
- package/src/ProfileView/components/ProfileFilters/useProfileFilters.ts +284 -0
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +103 -0
- package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +30 -18
- package/src/ProfileView/components/Toolbars/index.tsx +5 -35
- package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +5 -12
- package/src/ProfileView/hooks/useVisualizationState.ts +0 -11
- package/src/ProfileView/index.tsx +1 -15
- package/src/ProfileViewWithData.tsx +9 -9
- package/src/Sandwich/index.tsx +5 -2
- package/src/Table/index.tsx +3 -44
- package/src/useQuery.tsx +11 -43
- package/dist/ProfileView/components/FilterByFunctionButton.d.ts +0 -3
- package/dist/ProfileView/components/FilterByFunctionButton.d.ts.map +0 -1
- package/dist/ProfileView/components/FilterByFunctionButton.js +0 -89
- package/src/ProfileView/components/FilterByFunctionButton.tsx +0 -128
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright 2022 The Parca Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { useCallback } from 'react';
|
|
15
|
+
import { Icon } from '@iconify/react';
|
|
16
|
+
import cx from 'classnames';
|
|
17
|
+
import { Button, Input, Select } from '@parca/components';
|
|
18
|
+
import { useProfileFilters } from './useProfileFilters';
|
|
19
|
+
export const isFilterComplete = (filter) => {
|
|
20
|
+
return (filter.value !== '' && filter.type != null && filter.field != null && filter.matchType != null);
|
|
21
|
+
};
|
|
22
|
+
const filterTypeItems = [
|
|
23
|
+
{
|
|
24
|
+
key: 'stack',
|
|
25
|
+
element: {
|
|
26
|
+
active: _jsx(_Fragment, { children: "Stack Filter" }),
|
|
27
|
+
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: "Stack Filter" }), _jsx("br", {}), _jsx("span", { className: "text-xs", children: "Filters entire call stacks" })] })),
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: 'frame',
|
|
32
|
+
element: {
|
|
33
|
+
active: _jsx(_Fragment, { children: "Frame Filter" }),
|
|
34
|
+
expanded: (_jsxs(_Fragment, { children: [_jsx("span", { children: "Frame Filter" }), _jsx("br", {}), _jsx("span", { className: "text-xs", children: "Filters individual frames" })] })),
|
|
35
|
+
},
|
|
36
|
+
},
|
|
37
|
+
];
|
|
38
|
+
const fieldItems = [
|
|
39
|
+
{
|
|
40
|
+
key: 'function_name',
|
|
41
|
+
element: {
|
|
42
|
+
active: _jsx(_Fragment, { children: "Function" }),
|
|
43
|
+
expanded: _jsx(_Fragment, { children: "Function Name" }),
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: 'binary',
|
|
48
|
+
element: {
|
|
49
|
+
active: _jsx(_Fragment, { children: "Binary" }),
|
|
50
|
+
expanded: _jsx(_Fragment, { children: "Binary/Executable Name" }),
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
key: 'system_name',
|
|
55
|
+
element: {
|
|
56
|
+
active: _jsx(_Fragment, { children: "System Name" }),
|
|
57
|
+
expanded: _jsx(_Fragment, { children: "System Name" }),
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: 'filename',
|
|
62
|
+
element: {
|
|
63
|
+
active: _jsx(_Fragment, { children: "Filename" }),
|
|
64
|
+
expanded: _jsx(_Fragment, { children: "Source Filename" }),
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'address',
|
|
69
|
+
element: {
|
|
70
|
+
active: _jsx(_Fragment, { children: "Address" }),
|
|
71
|
+
expanded: _jsx(_Fragment, { children: "Memory Address" }),
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
key: 'line_number',
|
|
76
|
+
element: {
|
|
77
|
+
active: _jsx(_Fragment, { children: "Line Number" }),
|
|
78
|
+
expanded: _jsx(_Fragment, { children: "Source Line Number" }),
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
];
|
|
82
|
+
const stringMatchTypeItems = [
|
|
83
|
+
{
|
|
84
|
+
key: 'equal',
|
|
85
|
+
element: {
|
|
86
|
+
active: _jsx(_Fragment, { children: "Equals" }),
|
|
87
|
+
expanded: _jsx(_Fragment, { children: "Equals" }),
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
key: 'not_equal',
|
|
92
|
+
element: {
|
|
93
|
+
active: _jsx(_Fragment, { children: "Not Equals" }),
|
|
94
|
+
expanded: _jsx(_Fragment, { children: "Not Equals" }),
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
key: 'contains',
|
|
99
|
+
element: {
|
|
100
|
+
active: _jsx(_Fragment, { children: "Contains" }),
|
|
101
|
+
expanded: _jsx(_Fragment, { children: "Contains" }),
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
key: 'not_contains',
|
|
106
|
+
element: {
|
|
107
|
+
active: _jsx(_Fragment, { children: "Not Contains" }),
|
|
108
|
+
expanded: _jsx(_Fragment, { children: "Not Contains" }),
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
];
|
|
112
|
+
const numberMatchTypeItems = [
|
|
113
|
+
{
|
|
114
|
+
key: 'equal',
|
|
115
|
+
element: {
|
|
116
|
+
active: _jsx(_Fragment, { children: "Equals" }),
|
|
117
|
+
expanded: _jsx(_Fragment, { children: "Equals" }),
|
|
118
|
+
},
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
key: 'not_equal',
|
|
122
|
+
element: {
|
|
123
|
+
active: _jsx(_Fragment, { children: "Not Equals" }),
|
|
124
|
+
expanded: _jsx(_Fragment, { children: "Not Equals" }),
|
|
125
|
+
},
|
|
126
|
+
},
|
|
127
|
+
];
|
|
128
|
+
const ProfileFilters = () => {
|
|
129
|
+
const { localFilters, appliedFilters, hasUnsavedChanges, onApplyFilters, addFilter, removeFilter, updateFilter, resetFilters, } = useProfileFilters();
|
|
130
|
+
const handleKeyDown = useCallback((e) => {
|
|
131
|
+
if (e.key === 'Enter') {
|
|
132
|
+
e.preventDefault();
|
|
133
|
+
if (e.currentTarget.value.trim() === '') {
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
onApplyFilters();
|
|
137
|
+
}
|
|
138
|
+
}, [onApplyFilters]);
|
|
139
|
+
const filtersToRender = localFilters.length > 0 ? localFilters : appliedFilters ?? [];
|
|
140
|
+
return (_jsxs("div", { className: "flex gap-2 w-full", children: [_jsxs("div", { className: "flex-1 flex flex-wrap gap-2", children: [filtersToRender.map(filter => {
|
|
141
|
+
const isNumberField = filter.field === 'address' || filter.field === 'line_number';
|
|
142
|
+
const matchTypeItems = isNumberField ? numberMatchTypeItems : stringMatchTypeItems;
|
|
143
|
+
return (_jsxs("div", { className: "flex items-center gap-0", children: [_jsx(Select, { items: filterTypeItems, selectedKey: filter.type, placeholder: "Select Filter", onSelection: key => {
|
|
144
|
+
const newType = key;
|
|
145
|
+
updateFilter(filter.id, {
|
|
146
|
+
type: newType,
|
|
147
|
+
field: filter.field ?? 'function_name',
|
|
148
|
+
matchType: filter.matchType ?? 'contains',
|
|
149
|
+
});
|
|
150
|
+
}, className: cx('rounded-l-md pr-1 gap-0 focus:z-50 focus:relative focus:outline-1 rounded-r-none ', filter.type != null ? 'border-r-0 w-28' : 'w-32') }), filter.type != null && (_jsxs(_Fragment, { children: [_jsx(Select, { items: fieldItems, selectedKey: filter.field ?? '', onSelection: key => {
|
|
151
|
+
const newField = key;
|
|
152
|
+
const isNewFieldNumber = newField === 'address' || newField === 'line_number';
|
|
153
|
+
const isCurrentFieldNumber = filter.field === 'address' || filter.field === 'line_number';
|
|
154
|
+
if (isNewFieldNumber !== isCurrentFieldNumber) {
|
|
155
|
+
updateFilter(filter.id, {
|
|
156
|
+
field: newField,
|
|
157
|
+
matchType: 'equal',
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
else {
|
|
161
|
+
updateFilter(filter.id, { field: newField });
|
|
162
|
+
}
|
|
163
|
+
}, className: "rounded-none border-r-0 w-32 pr-1 gap-0 focus:z-50 focus:relative focus:outline-1" }), _jsx(Select, { items: matchTypeItems, selectedKey: filter.matchType ?? '', onSelection: key => updateFilter(filter.id, { matchType: key }), className: "rounded-none border-r-0 pr-1 gap-0 focus:z-50 focus:relative focus:outline-1" }), _jsx(Input, { placeholder: "Value", value: filter.value, onChange: e => updateFilter(filter.id, { value: e.target.value }), onKeyDown: handleKeyDown, className: "rounded-none w-36 text-sm focus:outline-1" })] })), _jsx(Button, { variant: "neutral", onClick: () => {
|
|
164
|
+
if (localFilters.length === 1) {
|
|
165
|
+
resetFilters();
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
removeFilter(filter.id);
|
|
169
|
+
}
|
|
170
|
+
}, className: cx('h-[38px] p-3', filter.type != null ? 'rounded-none rounded-r-md' : 'rounded-l-none rounded-r-md'), children: _jsx(Icon, { icon: "mdi:close", className: "h-4 w-4" }) })] }, filter.id));
|
|
171
|
+
}), localFilters.length > 0 && (_jsx(Button, { variant: "neutral", onClick: addFilter, className: "p-3 h-[38px]", children: _jsx(Icon, { icon: "mdi:filter-plus-outline", className: "h-4 w-4" }) })), localFilters.length === 0 && (appliedFilters?.length ?? 0) === 0 && (_jsxs(Button, { variant: "neutral", onClick: addFilter, className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "mdi:filter-outline", className: "h-4 w-4" }), _jsx("span", { children: "Filter" })] }))] }), localFilters.length > 0 && hasUnsavedChanges && localFilters.some(isFilterComplete) && (_jsx(Button, { variant: "primary", onClick: onApplyFilters, className: cx('flex items-center gap-2 self-end'), children: _jsx("span", { children: "Apply" }) }))] }));
|
|
172
|
+
};
|
|
173
|
+
export default ProfileFilters;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type Filter } from '@parca/client';
|
|
2
|
+
import { type ProfileFilter } from '@parca/store';
|
|
3
|
+
export type { ProfileFilter };
|
|
4
|
+
export declare const useProfileFilters: () => {
|
|
5
|
+
localFilters: ProfileFilter[];
|
|
6
|
+
appliedFilters: ProfileFilter[];
|
|
7
|
+
protoFilters: Filter[];
|
|
8
|
+
hasUnsavedChanges: boolean;
|
|
9
|
+
onApplyFilters: () => void;
|
|
10
|
+
addFilter: () => void;
|
|
11
|
+
excludeBinary: (binaryName: string) => void;
|
|
12
|
+
removeExcludeBinary: (binaryName: string) => void;
|
|
13
|
+
removeFilter: (id: string) => void;
|
|
14
|
+
updateFilter: (id: string, updates: Partial<ProfileFilter>) => void;
|
|
15
|
+
resetFilters: () => void;
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=useProfileFilters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProfileFilters.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/useProfileFilters.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,KAAK,MAAM,EAAC,MAAM,eAAe,CAAC;AAC1C,OAAO,EAKL,KAAK,aAAa,EACnB,MAAM,cAAc,CAAC;AAItB,YAAY,EAAC,aAAa,EAAC,CAAC;AAoF5B,eAAO,MAAM,iBAAiB,QAAO;IACnC,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,iBAAiB,EAAE,OAAO,CAAC;IAC3B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,aAAa,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,mBAAmB,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACnC,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,CAAC,aAAa,CAAC,KAAK,IAAI,CAAC;IACpE,YAAY,EAAE,MAAM,IAAI,CAAC;CAkK1B,CAAC"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
// Copyright 2022 The Parca 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
|
+
import { useCallback, useEffect, useMemo } from 'react';
|
|
14
|
+
import { selectLocalFilters, setLocalFilters, useAppDispatch, useAppSelector, } from '@parca/store';
|
|
15
|
+
import { useProfileFiltersUrlState } from './useProfileFiltersUrlState';
|
|
16
|
+
// Convert ProfileFilter[] to protobuf Filter[] matching the expected structure
|
|
17
|
+
const convertToProtoFilters = (profileFilters) => {
|
|
18
|
+
return profileFilters
|
|
19
|
+
.filter(f => f.value !== '' && f.type != null && f.field != null && f.matchType != null) // Only include complete filters with values
|
|
20
|
+
.map(f => {
|
|
21
|
+
// Build the condition based on field type
|
|
22
|
+
const isNumberField = f.field === 'address' || f.field === 'line_number';
|
|
23
|
+
let condition;
|
|
24
|
+
if (isNumberField) {
|
|
25
|
+
const numValue = BigInt(f.value);
|
|
26
|
+
condition = {
|
|
27
|
+
condition: f.matchType === 'equal'
|
|
28
|
+
? { oneofKind: 'equal', equal: numValue }
|
|
29
|
+
: { oneofKind: 'notEqual', notEqual: numValue },
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
condition = {
|
|
34
|
+
condition: f.matchType === 'equal'
|
|
35
|
+
? { oneofKind: 'equal', equal: f.value }
|
|
36
|
+
: f.matchType === 'not_equal'
|
|
37
|
+
? { oneofKind: 'notEqual', notEqual: f.value }
|
|
38
|
+
: f.matchType === 'contains'
|
|
39
|
+
? { oneofKind: 'contains', contains: f.value }
|
|
40
|
+
: { oneofKind: 'notContains', notContains: f.value },
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
// Create FilterCriteria
|
|
44
|
+
const criteria = {};
|
|
45
|
+
switch (f.field) {
|
|
46
|
+
case 'function_name':
|
|
47
|
+
criteria.functionName = condition;
|
|
48
|
+
break;
|
|
49
|
+
case 'binary':
|
|
50
|
+
criteria.binary = condition;
|
|
51
|
+
break;
|
|
52
|
+
case 'system_name':
|
|
53
|
+
criteria.systemName = condition;
|
|
54
|
+
break;
|
|
55
|
+
case 'filename':
|
|
56
|
+
criteria.filename = condition;
|
|
57
|
+
break;
|
|
58
|
+
case 'address':
|
|
59
|
+
criteria.address = condition;
|
|
60
|
+
break;
|
|
61
|
+
case 'line_number':
|
|
62
|
+
criteria.lineNumber = condition;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
// Create the appropriate filter type with proper oneofKind structure
|
|
66
|
+
if (f.type === 'stack') {
|
|
67
|
+
return {
|
|
68
|
+
filter: {
|
|
69
|
+
oneofKind: 'stackFilter',
|
|
70
|
+
stackFilter: {
|
|
71
|
+
filter: {
|
|
72
|
+
oneofKind: 'criteria',
|
|
73
|
+
criteria,
|
|
74
|
+
},
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
return {
|
|
81
|
+
filter: {
|
|
82
|
+
oneofKind: 'frameFilter',
|
|
83
|
+
frameFilter: {
|
|
84
|
+
filter: {
|
|
85
|
+
oneofKind: 'criteria',
|
|
86
|
+
criteria,
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
};
|
|
94
|
+
export const useProfileFilters = () => {
|
|
95
|
+
const { appliedFilters, setAppliedFilters } = useProfileFiltersUrlState();
|
|
96
|
+
const dispatch = useAppDispatch();
|
|
97
|
+
const localFilters = useAppSelector(selectLocalFilters);
|
|
98
|
+
useEffect(() => {
|
|
99
|
+
if (appliedFilters != null && appliedFilters.length > 0) {
|
|
100
|
+
// Check if they're different to avoid unnecessary updates
|
|
101
|
+
const areFiltersEqual = appliedFilters.length === localFilters.length &&
|
|
102
|
+
appliedFilters.every((applied, index) => {
|
|
103
|
+
const local = localFilters[index];
|
|
104
|
+
return (local != null &&
|
|
105
|
+
applied.type === local.type &&
|
|
106
|
+
applied.field === local.field &&
|
|
107
|
+
applied.matchType === local.matchType &&
|
|
108
|
+
applied.value === local.value);
|
|
109
|
+
});
|
|
110
|
+
if (!areFiltersEqual) {
|
|
111
|
+
dispatch(setLocalFilters(appliedFilters));
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else if (appliedFilters != null && appliedFilters.length === 0 && localFilters.length > 0) {
|
|
115
|
+
dispatch(setLocalFilters([]));
|
|
116
|
+
}
|
|
117
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
118
|
+
}, []);
|
|
119
|
+
const hasUnsavedChanges = useMemo(() => {
|
|
120
|
+
const localWithValues = localFilters.filter(f => f.value !== '');
|
|
121
|
+
const appliedWithValues = (appliedFilters ?? []).filter(f => f.value !== '');
|
|
122
|
+
if (localWithValues.length !== appliedWithValues.length)
|
|
123
|
+
return true;
|
|
124
|
+
return !localWithValues.every((local, index) => {
|
|
125
|
+
const applied = appliedWithValues[index];
|
|
126
|
+
return (local.type === applied?.type &&
|
|
127
|
+
local.field === applied?.field &&
|
|
128
|
+
local.matchType === applied?.matchType &&
|
|
129
|
+
local.value === applied?.value);
|
|
130
|
+
});
|
|
131
|
+
}, [localFilters, appliedFilters]);
|
|
132
|
+
const addFilter = useCallback(() => {
|
|
133
|
+
const newFilter = {
|
|
134
|
+
id: `filter-${Date.now()}-${Math.random()}`,
|
|
135
|
+
value: '',
|
|
136
|
+
};
|
|
137
|
+
dispatch(setLocalFilters([...localFilters, newFilter]));
|
|
138
|
+
}, [dispatch, localFilters]);
|
|
139
|
+
const excludeBinary = useCallback((binaryName) => {
|
|
140
|
+
// Check if this binary is already being filtered with not_contains
|
|
141
|
+
const existingFilter = (appliedFilters ?? []).find(f => f.type === 'frame' &&
|
|
142
|
+
f.field === 'binary' &&
|
|
143
|
+
f.matchType === 'not_contains' &&
|
|
144
|
+
f.value === binaryName);
|
|
145
|
+
if (existingFilter != null) {
|
|
146
|
+
return; // Already exists, don't add duplicate
|
|
147
|
+
}
|
|
148
|
+
const newFilter = {
|
|
149
|
+
id: `filter-${Date.now()}-${Math.random()}`,
|
|
150
|
+
type: 'frame',
|
|
151
|
+
field: 'binary',
|
|
152
|
+
matchType: 'not_contains',
|
|
153
|
+
value: binaryName,
|
|
154
|
+
};
|
|
155
|
+
dispatch(setLocalFilters([...localFilters, newFilter]));
|
|
156
|
+
// Auto-apply the filter since it has a value
|
|
157
|
+
const filtersToApply = [...(appliedFilters ?? []), newFilter];
|
|
158
|
+
setAppliedFilters(filtersToApply);
|
|
159
|
+
}, [appliedFilters, setAppliedFilters, dispatch, localFilters]);
|
|
160
|
+
const removeExcludeBinary = useCallback((binaryName) => {
|
|
161
|
+
// Search for the exclude filter (not_contains) for this binary
|
|
162
|
+
const filterToRemove = (appliedFilters ?? []).find(f => f.type === 'frame' &&
|
|
163
|
+
f.field === 'binary' &&
|
|
164
|
+
f.matchType === 'not_contains' &&
|
|
165
|
+
f.value === binaryName);
|
|
166
|
+
if (filterToRemove != null) {
|
|
167
|
+
// Remove the filter from applied filters
|
|
168
|
+
const updatedAppliedFilters = (appliedFilters ?? []).filter(f => f.id !== filterToRemove.id);
|
|
169
|
+
setAppliedFilters(updatedAppliedFilters);
|
|
170
|
+
// Also remove from local filters
|
|
171
|
+
const updatedLocalFilters = localFilters.filter(f => f.id !== filterToRemove.id);
|
|
172
|
+
dispatch(setLocalFilters(updatedLocalFilters));
|
|
173
|
+
}
|
|
174
|
+
}, [appliedFilters, setAppliedFilters, dispatch, localFilters]);
|
|
175
|
+
const removeFilter = useCallback((id) => {
|
|
176
|
+
dispatch(setLocalFilters(localFilters.filter(f => f.id !== id)));
|
|
177
|
+
}, [dispatch, localFilters]);
|
|
178
|
+
const updateFilter = useCallback((id, updates) => {
|
|
179
|
+
dispatch(setLocalFilters(localFilters.map(f => (f.id === id ? { ...f, ...updates } : f))));
|
|
180
|
+
}, [dispatch, localFilters]);
|
|
181
|
+
const resetFilters = useCallback(() => {
|
|
182
|
+
dispatch(setLocalFilters([]));
|
|
183
|
+
setAppliedFilters([]);
|
|
184
|
+
}, [dispatch, setAppliedFilters]);
|
|
185
|
+
const onApplyFilters = useCallback(() => {
|
|
186
|
+
const validFilters = localFilters.filter(f => f.value !== '' && f.type != null && f.field != null && f.matchType != null);
|
|
187
|
+
const filtersToApply = validFilters.map((f, index) => ({
|
|
188
|
+
...f,
|
|
189
|
+
id: `filter-${Date.now()}-${index}`,
|
|
190
|
+
}));
|
|
191
|
+
setAppliedFilters(filtersToApply);
|
|
192
|
+
}, [localFilters, setAppliedFilters]);
|
|
193
|
+
const protoFilters = useMemo(() => {
|
|
194
|
+
return convertToProtoFilters(appliedFilters ?? []);
|
|
195
|
+
}, [appliedFilters]);
|
|
196
|
+
return {
|
|
197
|
+
localFilters,
|
|
198
|
+
appliedFilters,
|
|
199
|
+
protoFilters,
|
|
200
|
+
hasUnsavedChanges,
|
|
201
|
+
onApplyFilters,
|
|
202
|
+
addFilter,
|
|
203
|
+
excludeBinary,
|
|
204
|
+
removeExcludeBinary,
|
|
205
|
+
removeFilter,
|
|
206
|
+
updateFilter,
|
|
207
|
+
resetFilters,
|
|
208
|
+
};
|
|
209
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ParamValueSetterCustom } from '@parca/components';
|
|
2
|
+
import { type ProfileFilter } from '@parca/store';
|
|
3
|
+
export declare const decodeProfileFilters: (encoded: string) => ProfileFilter[];
|
|
4
|
+
export declare const useProfileFiltersUrlState: () => {
|
|
5
|
+
appliedFilters: ProfileFilter[];
|
|
6
|
+
setAppliedFilters: ParamValueSetterCustom<ProfileFilter[]>;
|
|
7
|
+
};
|
|
8
|
+
//# sourceMappingURL=useProfileFiltersUrlState.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useProfileFiltersUrlState.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts"],"names":[],"mappings":"AAaA,OAAO,EAAoB,KAAK,sBAAsB,EAAC,MAAM,mBAAmB,CAAC;AACjF,OAAO,EAAC,KAAK,aAAa,EAAC,MAAM,cAAc,CAAC;AA8ChD,eAAO,MAAM,oBAAoB,GAAI,SAAS,MAAM,KAAG,aAAa,EAmBnE,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAO;IAC3C,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,iBAAiB,EAAE,sBAAsB,CAAC,aAAa,EAAE,CAAC,CAAC;CAmB5D,CAAC"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// Copyright 2022 The Parca 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
|
+
import { useURLStateCustom } from '@parca/components';
|
|
14
|
+
// Compact encoding mappings
|
|
15
|
+
const TYPE_MAP = {
|
|
16
|
+
stack: 's',
|
|
17
|
+
frame: 'f',
|
|
18
|
+
};
|
|
19
|
+
const FIELD_MAP = {
|
|
20
|
+
function_name: 'fn',
|
|
21
|
+
binary: 'b',
|
|
22
|
+
system_name: 'sn',
|
|
23
|
+
filename: 'f',
|
|
24
|
+
address: 'a',
|
|
25
|
+
line_number: 'ln',
|
|
26
|
+
};
|
|
27
|
+
const MATCH_MAP = {
|
|
28
|
+
equal: '=',
|
|
29
|
+
not_equal: '!=',
|
|
30
|
+
contains: '~',
|
|
31
|
+
not_contains: '!~',
|
|
32
|
+
};
|
|
33
|
+
// Reverse mappings for decoding
|
|
34
|
+
const TYPE_MAP_REVERSE = Object.fromEntries(Object.entries(TYPE_MAP).map(([k, v]) => [v, k]));
|
|
35
|
+
const FIELD_MAP_REVERSE = Object.fromEntries(Object.entries(FIELD_MAP).map(([k, v]) => [v, k]));
|
|
36
|
+
const MATCH_MAP_REVERSE = Object.fromEntries(Object.entries(MATCH_MAP).map(([k, v]) => [v, k]));
|
|
37
|
+
// Encode filters to compact string format
|
|
38
|
+
const encodeProfileFilters = (filters) => {
|
|
39
|
+
if (filters.length === 0)
|
|
40
|
+
return '';
|
|
41
|
+
return filters
|
|
42
|
+
.filter(f => f.value !== '' && f.type != null && f.field != null && f.matchType != null)
|
|
43
|
+
.map(f => {
|
|
44
|
+
const type = TYPE_MAP[f.type];
|
|
45
|
+
const field = FIELD_MAP[f.field];
|
|
46
|
+
const match = MATCH_MAP[f.matchType];
|
|
47
|
+
const value = encodeURIComponent(f.value);
|
|
48
|
+
return `${type}:${field}:${match}:${value}`;
|
|
49
|
+
})
|
|
50
|
+
.join(',');
|
|
51
|
+
};
|
|
52
|
+
// Decode filters from compact string format
|
|
53
|
+
export const decodeProfileFilters = (encoded) => {
|
|
54
|
+
if (encoded === '' || encoded === undefined)
|
|
55
|
+
return [];
|
|
56
|
+
try {
|
|
57
|
+
return encoded.split(',').map((filter, index) => {
|
|
58
|
+
const [type, field, match, ...valueParts] = filter.split(':');
|
|
59
|
+
const value = decodeURIComponent(valueParts.join(':')); // Handle values with colons
|
|
60
|
+
return {
|
|
61
|
+
id: `filter-${Date.now()}-${index}`,
|
|
62
|
+
type: TYPE_MAP_REVERSE[type],
|
|
63
|
+
field: FIELD_MAP_REVERSE[field],
|
|
64
|
+
matchType: MATCH_MAP_REVERSE[match],
|
|
65
|
+
value,
|
|
66
|
+
};
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch {
|
|
70
|
+
return [];
|
|
71
|
+
}
|
|
72
|
+
};
|
|
73
|
+
export const useProfileFiltersUrlState = () => {
|
|
74
|
+
// Store applied filters in URL state for persistence using compact encoding
|
|
75
|
+
const [appliedFilters, setAppliedFilters] = useURLStateCustom('profile_filters', {
|
|
76
|
+
parse: value => {
|
|
77
|
+
return decodeProfileFilters(value);
|
|
78
|
+
},
|
|
79
|
+
stringify: value => {
|
|
80
|
+
return encodeProfileFilters(value);
|
|
81
|
+
},
|
|
82
|
+
});
|
|
83
|
+
return {
|
|
84
|
+
appliedFilters,
|
|
85
|
+
setAppliedFilters,
|
|
86
|
+
};
|
|
87
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"MultiLevelDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAkK1C,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,
|
|
1
|
+
{"version":3,"file":"MultiLevelDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAQtE,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAkK1C,UAAU,uBAAuB;IAC/B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAAE,CAAC,uBAAuB,CAqPzD,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -71,13 +71,14 @@ const MenuItem = ({ label, items, onclick, onSelect, path = [], id, closeDropdow
|
|
|
71
71
|
}, path: [...path, label], closeDropdown: closeDropdown, isNested: true, activeValueForSortBy: activeValueForSortBy, activeValueForColorBy: activeValueForColorBy, activeValuesForLevel: activeValuesForLevel }, index))) }))] })) }) }));
|
|
72
72
|
};
|
|
73
73
|
const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isTableVizOnly, }) => {
|
|
74
|
+
const dropdownRef = useRef(null);
|
|
75
|
+
const [shouldOpenLeft, setShouldOpenLeft] = useState(false);
|
|
74
76
|
const [storeSortBy] = useURLState('sort_by', {
|
|
75
77
|
defaultValue: FIELD_FUNCTION_NAME,
|
|
76
78
|
});
|
|
77
79
|
const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
|
|
78
|
-
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
79
80
|
const [colorBy, setColorBy] = useURLState('color_by');
|
|
80
|
-
const [hiddenBinaries, setHiddenBinaries] = useURLState('
|
|
81
|
+
const [hiddenBinaries, setHiddenBinaries] = useURLState('hidden_binaries', {
|
|
81
82
|
defaultValue: [],
|
|
82
83
|
alwaysReturnArray: true,
|
|
83
84
|
});
|
|
@@ -91,6 +92,21 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
|
|
|
91
92
|
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
92
93
|
const [compareAbsolute = compareAbsoluteDefault, setCompareAbsolute] = useURLState('compare_absolute');
|
|
93
94
|
const isCompareAbsolute = compareAbsolute === 'true';
|
|
95
|
+
useEffect(() => {
|
|
96
|
+
const checkOverflow = () => {
|
|
97
|
+
if (dropdownRef.current !== null) {
|
|
98
|
+
const rect = dropdownRef.current.getBoundingClientRect();
|
|
99
|
+
const viewportWidth = window.innerWidth;
|
|
100
|
+
const menuWidth = isTableVizOnly ? 256 : 320; // w-64 = 256px, w-80 = 320px
|
|
101
|
+
const spaceOnRight = viewportWidth - rect.right;
|
|
102
|
+
const spaceOnLeft = rect.left;
|
|
103
|
+
setShouldOpenLeft(spaceOnRight < menuWidth && spaceOnLeft >= menuWidth);
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
checkOverflow();
|
|
107
|
+
window.addEventListener('resize', checkOverflow);
|
|
108
|
+
return () => window.removeEventListener('resize', checkOverflow);
|
|
109
|
+
}, [isTableVizOnly]);
|
|
94
110
|
const handleBinaryToggle = (index) => {
|
|
95
111
|
const updatedBinaries = [...hiddenBinaries];
|
|
96
112
|
updatedBinaries.splice(index, 1);
|
|
@@ -100,7 +116,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
|
|
|
100
116
|
setStoreColorStackLegend(value);
|
|
101
117
|
}, [setStoreColorStackLegend]);
|
|
102
118
|
const resetLegend = () => {
|
|
103
|
-
|
|
119
|
+
setHiddenBinaries([]);
|
|
104
120
|
};
|
|
105
121
|
const menuItems = [
|
|
106
122
|
{
|
|
@@ -171,12 +187,6 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
|
|
|
171
187
|
hide: !compareMode,
|
|
172
188
|
icon: isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven',
|
|
173
189
|
},
|
|
174
|
-
{
|
|
175
|
-
label: 'Highlight matching nodes after filtering',
|
|
176
|
-
hide: !!isTableVizOnly,
|
|
177
|
-
customSubmenu: (_jsx(SwitchMenuItem, { label: "Highlight matching nodes after filtering", id: "h-highlight-after-filtering", userPreferenceDetails: USER_PREFERENCES.HIGHTLIGHT_AFTER_FILTERING })),
|
|
178
|
-
renderAsDiv: true,
|
|
179
|
-
},
|
|
180
190
|
{
|
|
181
191
|
label: 'Dock Graph MetaInfo',
|
|
182
192
|
hide: !!isTableVizOnly,
|
|
@@ -191,7 +201,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
|
|
|
191
201
|
},
|
|
192
202
|
{
|
|
193
203
|
label: 'Reset Legend',
|
|
194
|
-
hide:
|
|
204
|
+
hide: hiddenBinaries === undefined || hiddenBinaries.length === 0,
|
|
195
205
|
onclick: () => resetLegend(),
|
|
196
206
|
id: 'h-reset-legend-button',
|
|
197
207
|
icon: 'system-uicons:reset',
|
|
@@ -207,7 +217,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
|
|
|
207
217
|
icon: 'ph:eye-closed',
|
|
208
218
|
},
|
|
209
219
|
];
|
|
210
|
-
return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "pajamas:preferences", className: "w-4 h-4" }), _jsx("span", { children: "Preferences" })] }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsx(Menu.Items, { className: cx(isTableVizOnly ? 'w-64' : 'w-80', 'absolute z-30
|
|
220
|
+
return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", ref: dropdownRef, children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "pajamas:preferences", className: "w-4 h-4" }), _jsx("span", { children: "Preferences" })] }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsx(Menu.Items, { className: cx(isTableVizOnly ? 'w-64' : 'w-80', 'absolute z-30 mt-2 py-2 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600', shouldOpenLeft ? 'right-0 origin-top-right' : 'left-0 origin-top-left'), children: menuItems
|
|
211
221
|
.filter(item => item.hide !== undefined && !item.hide)
|
|
212
222
|
.map((item, index) => (_jsx(MenuItem, { ...item, onSelect: onSelect, closeDropdown: close, activeValueForSortBy: storeSortBy, activeValueForColorBy: colorBy === undefined || colorBy === '' ? 'binary' : colorBy, activeValuesForLevel: groupBy, renderAsDiv: item.renderAsDiv }, index))) }))] })) }) }));
|
|
213
223
|
};
|
|
@@ -16,12 +16,9 @@ export interface VisualisationToolbarProps {
|
|
|
16
16
|
profileType?: ProfileType;
|
|
17
17
|
total: bigint;
|
|
18
18
|
filtered: bigint;
|
|
19
|
-
currentSearchString?: string;
|
|
20
|
-
setSearchString?: (value: string) => void;
|
|
21
19
|
groupByLabels: string[];
|
|
22
20
|
preferencesModal?: boolean;
|
|
23
21
|
profileViewExternalSubActions?: React.ReactNode;
|
|
24
|
-
clearSelection: () => void;
|
|
25
22
|
setGroupByLabels: (labels: string[]) => void;
|
|
26
23
|
showVisualizationSelector?: boolean;
|
|
27
24
|
sandwichFunctionName?: string;
|
|
@@ -30,8 +27,6 @@ export interface TableToolbarProps {
|
|
|
30
27
|
profileType?: ProfileType;
|
|
31
28
|
total: bigint;
|
|
32
29
|
filtered: bigint;
|
|
33
|
-
clearSelection: () => void;
|
|
34
|
-
currentSearchString?: string;
|
|
35
30
|
}
|
|
36
31
|
export interface FlameGraphToolbarProps {
|
|
37
32
|
curPath: CurrentPathFrame[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAiBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAsF9D,CAAC"}
|