@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.
Files changed (85) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  3. package/dist/ProfileExplorer/ProfileExplorerCompare.js +1 -3
  4. package/dist/ProfileExplorer/index.d.ts.map +1 -1
  5. package/dist/ProfileExplorer/index.js +5 -8
  6. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
  7. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +0 -2
  8. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts +0 -1
  9. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts.map +1 -1
  10. package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +2 -11
  11. package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
  12. package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +6 -14
  13. package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
  14. package/dist/ProfileSelector/useAutoQuerySelector.js +1 -1
  15. package/dist/ProfileSource.d.ts +4 -11
  16. package/dist/ProfileSource.d.ts.map +1 -1
  17. package/dist/ProfileSource.js +6 -14
  18. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
  19. package/dist/ProfileView/components/ColorStackLegend.js +14 -10
  20. package/dist/ProfileView/components/DashboardItems/index.d.ts +1 -3
  21. package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
  22. package/dist/ProfileView/components/DashboardItems/index.js +2 -2
  23. package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts.map +1 -1
  24. package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +14 -1
  25. package/dist/ProfileView/components/InvertCallStack/index.js +1 -1
  26. package/dist/ProfileView/components/ProfileFilters/index.d.ts +5 -0
  27. package/dist/ProfileView/components/ProfileFilters/index.d.ts.map +1 -0
  28. package/dist/ProfileView/components/ProfileFilters/index.js +173 -0
  29. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts +17 -0
  30. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.d.ts.map +1 -0
  31. package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +209 -0
  32. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +8 -0
  33. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -0
  34. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +87 -0
  35. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
  36. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +21 -11
  37. package/dist/ProfileView/components/Toolbars/index.d.ts +0 -5
  38. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  39. package/dist/ProfileView/components/Toolbars/index.js +6 -6
  40. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
  41. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +3 -12
  42. package/dist/ProfileView/hooks/useVisualizationState.d.ts +0 -3
  43. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  44. package/dist/ProfileView/hooks/useVisualizationState.js +0 -7
  45. package/dist/ProfileView/index.d.ts.map +1 -1
  46. package/dist/ProfileView/index.js +3 -5
  47. package/dist/ProfileViewWithData.d.ts.map +1 -1
  48. package/dist/ProfileViewWithData.js +8 -7
  49. package/dist/Sandwich/index.d.ts.map +1 -1
  50. package/dist/Sandwich/index.js +4 -2
  51. package/dist/Table/index.d.ts +0 -2
  52. package/dist/Table/index.d.ts.map +1 -1
  53. package/dist/Table/index.js +5 -32
  54. package/dist/styles.css +1 -1
  55. package/dist/useQuery.d.ts +1 -1
  56. package/dist/useQuery.d.ts.map +1 -1
  57. package/dist/useQuery.js +7 -40
  58. package/package.json +7 -7
  59. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +0 -4
  60. package/src/ProfileExplorer/index.tsx +4 -13
  61. package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +0 -2
  62. package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +1 -14
  63. package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +4 -16
  64. package/src/ProfileSelector/useAutoQuerySelector.ts +1 -2
  65. package/src/ProfileSource.tsx +6 -49
  66. package/src/ProfileView/components/ColorStackLegend.tsx +16 -12
  67. package/src/ProfileView/components/DashboardItems/index.tsx +0 -6
  68. package/src/ProfileView/components/GroupByLabelsDropdown/index.tsx +15 -2
  69. package/src/ProfileView/components/InvertCallStack/index.tsx +1 -1
  70. package/src/ProfileView/components/ProfileFilters/index.tsx +294 -0
  71. package/src/ProfileView/components/ProfileFilters/useProfileFilters.ts +284 -0
  72. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +103 -0
  73. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +30 -18
  74. package/src/ProfileView/components/Toolbars/index.tsx +5 -35
  75. package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +5 -12
  76. package/src/ProfileView/hooks/useVisualizationState.ts +0 -11
  77. package/src/ProfileView/index.tsx +1 -15
  78. package/src/ProfileViewWithData.tsx +9 -9
  79. package/src/Sandwich/index.tsx +5 -2
  80. package/src/Table/index.tsx +3 -44
  81. package/src/useQuery.tsx +11 -43
  82. package/dist/ProfileView/components/FilterByFunctionButton.d.ts +0 -3
  83. package/dist/ProfileView/components/FilterByFunctionButton.d.ts.map +0 -1
  84. package/dist/ProfileView/components/FilterByFunctionButton.js +0 -89
  85. package/src/ProfileView/components/FilterByFunctionButton.tsx +0 -128
package/dist/useQuery.js CHANGED
@@ -10,11 +10,15 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
+ import { useMemo } from 'react';
13
14
  import { useGrpcMetadata } from '@parca/components';
14
15
  import useGrpcQuery from './useGrpcQuery';
15
16
  export const useQuery = (client, profileSource, reportType, options) => {
16
17
  const { skip = false } = options ?? {};
17
18
  const metadata = useGrpcMetadata();
19
+ const protoFiltersKey = useMemo(() => {
20
+ return JSON.stringify(options?.protoFilters ?? []);
21
+ }, [options?.protoFilters]);
18
22
  const { data, isLoading, error } = useGrpcQuery({
19
23
  key: [
20
24
  'query',
@@ -26,9 +30,8 @@ export const useQuery = (client, profileSource, reportType, options) => {
26
30
  options?.sourceOnly,
27
31
  options?.sourceOnly === true ? '' : options?.sourceFilename,
28
32
  options?.invertCallStack ?? false,
29
- options?.binaryFrameFilter ?? '',
30
- profileSource.excludeFunction ?? false,
31
33
  options?.sandwichByFunction ?? '',
34
+ protoFiltersKey,
32
35
  ],
33
36
  queryFn: async () => {
34
37
  const req = profileSource.QueryRequest();
@@ -45,49 +48,13 @@ export const useQuery = (client, profileSource, reportType, options) => {
45
48
  };
46
49
  }
47
50
  req.invertCallStack = options?.invertCallStack ?? false;
48
- // Handle filter from ProfileSource (filter by function toolbar)
49
- const functionToFilter = req.filterQuery;
50
- if (functionToFilter !== undefined && functionToFilter !== '') {
51
- req.filter = [
52
- ...req.filter,
53
- {
54
- filter: {
55
- oneofKind: 'stackFilter',
56
- stackFilter: {
57
- filter: {
58
- oneofKind: 'functionNameStackFilter',
59
- functionNameStackFilter: {
60
- functionToFilter,
61
- exclude: profileSource.excludeFunction ?? false,
62
- },
63
- },
64
- },
65
- },
66
- },
67
- ];
51
+ if (options?.protoFilters != null && options?.protoFilters?.length > 0) {
52
+ req.filter = options.protoFilters;
68
53
  }
69
54
  // Handle sandwich view filter separately
70
55
  if (options?.sandwichByFunction !== undefined) {
71
56
  req.sandwichByFunction = options.sandwichByFunction;
72
57
  }
73
- if (options?.binaryFrameFilter !== undefined && options?.binaryFrameFilter.length > 0) {
74
- req.filter = [
75
- ...req.filter,
76
- {
77
- filter: {
78
- oneofKind: 'frameFilter',
79
- frameFilter: {
80
- filter: {
81
- oneofKind: 'binaryFrameFilter',
82
- binaryFrameFilter: {
83
- includeBinaries: options?.binaryFrameFilter ?? [],
84
- },
85
- },
86
- },
87
- },
88
- },
89
- ];
90
- }
91
58
  try {
92
59
  const { response } = await client.query(req, { meta: metadata });
93
60
  return response;
package/package.json CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.19",
3
+ "version": "0.19.21",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
7
7
  "@headlessui/react": "^1.7.19",
8
8
  "@iconify/react": "^4.0.0",
9
- "@parca/client": "0.17.2",
10
- "@parca/components": "0.16.348",
9
+ "@parca/client": "0.17.3",
10
+ "@parca/components": "0.16.350",
11
11
  "@parca/dynamicsize": "0.16.65",
12
- "@parca/hooks": "0.0.93",
12
+ "@parca/hooks": "0.0.95",
13
13
  "@parca/icons": "0.16.72",
14
14
  "@parca/parser": "0.16.79",
15
- "@parca/store": "0.16.177",
16
- "@parca/utilities": "0.0.102",
15
+ "@parca/store": "0.16.179",
16
+ "@parca/utilities": "0.0.104",
17
17
  "@popperjs/core": "^2.11.8",
18
18
  "@protobuf-ts/runtime-rpc": "^2.5.0",
19
19
  "@storybook/preview-api": "^8.4.3",
@@ -78,5 +78,5 @@
78
78
  "access": "public",
79
79
  "registry": "https://registry.npmjs.org/"
80
80
  },
81
- "gitHead": "55c867baa7c927d7184bc4811b0543f641d09633"
81
+ "gitHead": "7413b38e28af33df4787abb9ca34e259ca9c5014"
82
82
  }
@@ -61,8 +61,6 @@ const ProfileExplorerCompare = ({
61
61
  };
62
62
 
63
63
  const [compareAbsolute] = useURLState('compare_absolute');
64
- const [functionFilter] = useURLState('filter_by_function');
65
- const [excludeFunction] = useURLState('exclude_function');
66
64
 
67
65
  return (
68
66
  <>
@@ -109,8 +107,6 @@ const ProfileExplorerCompare = ({
109
107
  new ProfileDiffSource(
110
108
  profileA.ProfileSource(),
111
109
  profileB.ProfileSource(),
112
- Array.isArray(functionFilter) ? functionFilter[0] : functionFilter,
113
- excludeFunction === 'true',
114
110
  compareAbsolute === 'true'
115
111
  )
116
112
  }
@@ -156,8 +156,6 @@ const ProfileExplorerApp = ({
156
156
  time_selection_b,
157
157
  compare_b,
158
158
  sum_by_b,
159
- filter_by_function,
160
- exclude_function,
161
159
  } = queryParams;
162
160
 
163
161
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -188,14 +186,12 @@ const ProfileExplorerApp = ({
188
186
  const profileA = ProfileSelectionFromParams(
189
187
  mergeFrom as string,
190
188
  mergeTo as string,
191
- selection_a,
192
- filter_by_function as string,
193
- exclude_function === 'true'
189
+ selection_a
194
190
  );
195
191
 
196
192
  setProfileA(profileA);
197
193
  // eslint-disable-next-line react-hooks/exhaustive-deps
198
- }, [merge_from_a, merge_to_a, selection_a, filter_by_function, exclude_function]);
194
+ }, [merge_from_a, merge_to_a, selection_a]);
199
195
 
200
196
  useEffect(() => {
201
197
  const mergeFrom = merge_from_b ?? undefined;
@@ -203,14 +199,12 @@ const ProfileExplorerApp = ({
203
199
  const profileB = ProfileSelectionFromParams(
204
200
  mergeFrom as string,
205
201
  mergeTo as string,
206
- selection_b,
207
- filter_by_function as string,
208
- exclude_function === 'true'
202
+ selection_b
209
203
  );
210
204
 
211
205
  setProfileB(profileB);
212
206
  // eslint-disable-next-line react-hooks/exhaustive-deps
213
- }, [merge_from_b, merge_to_b, selection_b, filter_by_function, exclude_function]);
207
+ }, [merge_from_b, merge_to_b, selection_b]);
214
208
 
215
209
  if (profileTypesLoading) {
216
210
  return <>{loader}</>;
@@ -352,7 +346,6 @@ const ProfileExplorerApp = ({
352
346
  to_a: q.to.toString(),
353
347
  time_selection_a: q.timeSelection,
354
348
  sum_by_a: sumByToParam(q.sumBy),
355
- filter_by_function: filter_by_function ?? '',
356
349
  ...mergeParams,
357
350
  },
358
351
  })
@@ -383,7 +376,6 @@ const ProfileExplorerApp = ({
383
376
  to_b: q.to.toString(),
384
377
  time_selection_b: q.timeSelection,
385
378
  sum_by_b: sumByToParam(q.sumBy),
386
- filter_by_function: filter_by_function ?? '',
387
379
  ...mergeParams,
388
380
  },
389
381
  })
@@ -401,7 +393,6 @@ const ProfileExplorerApp = ({
401
393
  ...{
402
394
  compare_a: 'false',
403
395
  compare_b: 'false',
404
- search_string: '',
405
396
  },
406
397
  });
407
398
  };
@@ -82,7 +82,6 @@ const ContextMenu = ({
82
82
  inlined,
83
83
  } = useGraphTooltipMetaInfo({table, row});
84
84
 
85
- const [_, setSearchString] = useURLState<string | undefined>('search_string');
86
85
  const [dashboardItems, setDashboardItems] = useURLState<string[]>('dashboard_items', {
87
86
  alwaysReturnArray: true,
88
87
  });
@@ -173,7 +172,6 @@ const ContextMenu = ({
173
172
  <Item
174
173
  id="show-in-table"
175
174
  onClick={() => {
176
- setSearchString(functionName);
177
175
  if (isSandwich) {
178
176
  setDashboardItems(['table']);
179
177
  } else {
@@ -17,7 +17,6 @@ import {Table} from 'apache-arrow';
17
17
  import cx from 'classnames';
18
18
 
19
19
  import {selectBinaries, useAppSelector} from '@parca/store';
20
- import {isSearchMatch} from '@parca/utilities';
21
20
 
22
21
  import 'react-contexify/dist/ReactContexify.css';
23
22
 
@@ -49,7 +48,6 @@ export interface FlameNodeProps {
49
48
  row: number;
50
49
  colors: colorByColors;
51
50
  colorBy: string;
52
- searchString?: string;
53
51
  darkMode: boolean;
54
52
  compareMode: boolean;
55
53
  onContextMenu: (e: React.MouseEvent, row: number) => void;
@@ -86,7 +84,6 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({
86
84
  colorBy,
87
85
  height,
88
86
  totalWidth,
89
- searchString,
90
87
  darkMode,
91
88
  compareMode,
92
89
  colorForSimilarNodes,
@@ -151,13 +148,6 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({
151
148
  return row === 0 ? 'root' : nodeLabel(table, row, binaries.length > 1);
152
149
  }, [table, row, binaries]);
153
150
 
154
- const {isHighlightEnabled = false, isHighlighted = false} = useMemo(() => {
155
- if (searchString === undefined || searchString === '') {
156
- return {isHighlightEnabled: false};
157
- }
158
- return {isHighlightEnabled: true, isHighlighted: isSearchMatch(searchString, name)};
159
- }, [searchString, name]);
160
-
161
151
  // Hide frames beyond effective depth limit
162
152
  if (effectiveDepth !== undefined && depth > effectiveDepth) {
163
153
  return <></>;
@@ -279,10 +269,7 @@ export const FlameNode = React.memo(function FlameNodeNoMemo({
279
269
  className={cx(
280
270
  shouldBeHighlighted
281
271
  ? `${colorForSimilarNodes} stroke-[3] [stroke-dasharray:6,4] [stroke-linecap:round] [stroke-linejoin:round] h-6`
282
- : 'stroke-white dark:stroke-gray-700',
283
- {
284
- 'opacity-50': isHighlightEnabled && !isHighlighted,
285
- }
272
+ : 'stroke-white dark:stroke-gray-700'
286
273
  )}
287
274
  />
288
275
  {width > 5 && (
@@ -32,6 +32,7 @@ import {getColorForFeature, selectDarkMode, useAppSelector} from '@parca/store';
32
32
  import {getLastItem, type ColorConfig} from '@parca/utilities';
33
33
 
34
34
  import {ProfileSource} from '../../ProfileSource';
35
+ import {useProfileFilters} from '../../ProfileView/components/ProfileFilters/useProfileFilters';
35
36
  import {useProfileViewContext} from '../../ProfileView/context/ProfileViewContext';
36
37
  import ContextMenuWrapper, {ContextMenuWrapperRef} from './ContextMenuWrapper';
37
38
  import {FlameNode, RowHeight, colorByColors} from './FlameGraphNodes';
@@ -139,7 +140,6 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
139
140
  curPath,
140
141
  profileType,
141
142
  profileSource,
142
- mappingsListFromMetadata,
143
143
  compareAbsolute,
144
144
  isFlameChart = false,
145
145
  isRenderedAsFlamegraph = false,
@@ -195,9 +195,8 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
195
195
  setSvgElement(svg.current);
196
196
  }, [tooltipId]);
197
197
 
198
- const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
198
+ const {excludeBinary} = useProfileFilters();
199
199
 
200
- const [currentSearchString] = useURLState('search_string');
201
200
  const {compareMode} = useProfileViewContext();
202
201
  const currentColorProfile = useCurrentColorProfile();
203
202
  const colorForSimilarNodes = currentColorProfile.colorForSimilarNodes;
@@ -276,18 +275,8 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
276
275
  );
277
276
 
278
277
  const hideBinary = (binaryToRemove: string): void => {
279
- // second/subsequent time filtering out a binary i.e. a binary has already been hidden
280
- // and we want to hide more binaries, we simply remove the binary from the binaryFrameFilter array in the URL.
281
- if (Array.isArray(binaryFrameFilter) && binaryFrameFilter.length > 0) {
282
- const newMappingsList = binaryFrameFilter.filter(mapping => mapping !== binaryToRemove);
283
-
284
- setBinaryFrameFilter(newMappingsList);
285
- return;
286
- }
287
-
288
- // first time hiding a binary
289
- const newMappingsList = mappingsListFromMetadata.filter(mapping => mapping !== binaryToRemove);
290
- setBinaryFrameFilter(newMappingsList);
278
+ // Add a new frame filter to hide this binary using the new ProfileFilters system
279
+ excludeBinary(binaryToRemove);
291
280
  };
292
281
 
293
282
  const handleRowClick = (row: number): void => {
@@ -386,7 +375,6 @@ export const FlameGraphArrow = memo(function FlameGraphArrow({
386
375
  colorBy={colorByValue}
387
376
  totalWidth={width ?? 1}
388
377
  height={RowHeight}
389
- searchString={(currentSearchString as string) ?? ''}
390
378
  darkMode={isDarkMode}
391
379
  compareMode={compareMode}
392
380
  colorForSimilarNodes={colorForSimilarNodes}
@@ -58,8 +58,7 @@ export const useAutoQuerySelector = ({
58
58
  const profileA = ProfileSelectionFromParams(
59
59
  querySelection.mergeFrom?.toString(),
60
60
  querySelection.mergeTo?.toString(),
61
- querySelection.expression,
62
- ''
61
+ querySelection.expression
63
62
  );
64
63
  const queryA = {
65
64
  expression: querySelection.expression,
@@ -27,7 +27,6 @@ export interface ProfileSource {
27
27
  ProfileType: () => ProfileType;
28
28
  DiffSelection: () => ProfileDiffSelection;
29
29
  toString: (timezone?: string) => string;
30
- excludeFunction?: boolean;
31
30
  }
32
31
 
33
32
  export interface ProfileSelection {
@@ -62,9 +61,7 @@ export function SuffixParams(params: {[key: string]: any}, suffix: string): {[ke
62
61
  export function ProfileSelectionFromParams(
63
62
  mergeFrom: string | undefined,
64
63
  mergeTo: string | undefined,
65
- selection: string | undefined,
66
- filterQuery?: string,
67
- excludeFunction?: boolean
64
+ selection: string | undefined
68
65
  ): ProfileSelection | null {
69
66
  if (
70
67
  mergeFrom !== undefined &&
@@ -85,9 +82,7 @@ export function ProfileSelectionFromParams(
85
82
  return new MergedProfileSelection(
86
83
  parseInt(mergeFrom),
87
84
  parseInt(mergeTo),
88
- Query.parse(selection),
89
- filterQuery,
90
- excludeFunction
85
+ Query.parse(selection)
91
86
  );
92
87
  }
93
88
 
@@ -98,29 +93,13 @@ export class MergedProfileSelection implements ProfileSelection {
98
93
  mergeFrom: number;
99
94
  mergeTo: number;
100
95
  query: Query;
101
- filterQuery: string | undefined;
102
- excludeFunction: boolean | undefined;
103
96
  profileSource: ProfileSource;
104
97
 
105
- constructor(
106
- mergeFrom: number,
107
- mergeTo: number,
108
- query: Query,
109
- filterQuery?: string,
110
- excludeFunction?: boolean
111
- ) {
98
+ constructor(mergeFrom: number, mergeTo: number, query: Query) {
112
99
  this.mergeFrom = mergeFrom;
113
100
  this.mergeTo = mergeTo;
114
101
  this.query = query;
115
- this.filterQuery = filterQuery;
116
- this.excludeFunction = excludeFunction;
117
- this.profileSource = new MergedProfileSource(
118
- this.mergeFrom,
119
- this.mergeTo,
120
- this.query,
121
- this.filterQuery,
122
- this.excludeFunction
123
- );
102
+ this.profileSource = new MergedProfileSource(this.mergeFrom, this.mergeTo, this.query);
124
103
  }
125
104
 
126
105
  ProfileName(): string {
@@ -147,22 +126,12 @@ export class MergedProfileSelection implements ProfileSelection {
147
126
  export class ProfileDiffSource implements ProfileSource {
148
127
  a: ProfileSource;
149
128
  b: ProfileSource;
150
- filterQuery: string | undefined;
151
- excludeFunction: boolean | undefined;
152
129
  profileType: ProfileType;
153
130
  absolute?: boolean;
154
131
 
155
- constructor(
156
- a: ProfileSource,
157
- b: ProfileSource,
158
- filterQuery?: string,
159
- excludeFunction?: boolean,
160
- absolute?: boolean
161
- ) {
132
+ constructor(a: ProfileSource, b: ProfileSource, absolute?: boolean) {
162
133
  this.a = a;
163
134
  this.b = b;
164
- this.filterQuery = filterQuery;
165
- this.excludeFunction = excludeFunction;
166
135
  this.profileType = a.ProfileType();
167
136
  this.absolute = absolute;
168
137
  }
@@ -183,7 +152,6 @@ export class ProfileDiffSource implements ProfileSource {
183
152
  },
184
153
  reportType: QueryRequest_ReportType.FLAMEGRAPH_ARROW,
185
154
  mode: QueryRequest_Mode.DIFF,
186
- filterQuery: this.filterQuery,
187
155
  filter: [],
188
156
  };
189
157
  }
@@ -216,22 +184,12 @@ export class MergedProfileSource implements ProfileSource {
216
184
  mergeFrom: number;
217
185
  mergeTo: number;
218
186
  query: Query;
219
- filterQuery: string | undefined;
220
- excludeFunction: boolean | undefined;
221
187
  profileType: ProfileType;
222
188
 
223
- constructor(
224
- mergeFrom: number,
225
- mergeTo: number,
226
- query: Query,
227
- filterQuery?: string,
228
- excludeFunction?: boolean
229
- ) {
189
+ constructor(mergeFrom: number, mergeTo: number, query: Query) {
230
190
  this.mergeFrom = mergeFrom;
231
191
  this.mergeTo = mergeTo;
232
192
  this.query = query;
233
- this.filterQuery = filterQuery;
234
- this.excludeFunction = excludeFunction;
235
193
  this.profileType = ProfileType.fromString(Query.parse(this.query.toString()).profileName());
236
194
  }
237
195
 
@@ -261,7 +219,6 @@ export class MergedProfileSource implements ProfileSource {
261
219
  },
262
220
  reportType: QueryRequest_ReportType.FLAMEGRAPH_ARROW,
263
221
  mode: QueryRequest_Mode.MERGE,
264
- filterQuery: this.filterQuery,
265
222
  filter: [],
266
223
  };
267
224
  }
@@ -22,6 +22,7 @@ import {EVERYTHING_ELSE, selectDarkMode, useAppSelector} from '@parca/store';
22
22
 
23
23
  import {getMappingColors} from '../../ProfileFlameGraph/FlameGraphArrow';
24
24
  import useMappingList from '../../ProfileFlameGraph/FlameGraphArrow/useMappingList';
25
+ import {useProfileFilters} from './ProfileFilters/useProfileFilters';
25
26
 
26
27
  interface Props {
27
28
  mappings?: string[];
@@ -40,10 +41,16 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
40
41
 
41
42
  const colorBy = colorByValue === 'binary' || colorByValue === undefined ? 'binary' : 'filename';
42
43
 
43
- const [currentSearchString, setSearchString] = useURLState<string[]>(`binary_frame_filter`, {
44
- alwaysReturnArray: true,
45
- defaultValue: [],
46
- });
44
+ const {appliedFilters, removeExcludeBinary, excludeBinary} = useProfileFilters();
45
+
46
+ // Get current binary filters from the new ProfileFilters system
47
+ const currentBinaryFilters = useMemo(() => {
48
+ return (appliedFilters ?? [])
49
+ .filter(f => f.type === 'frame' && f.field === 'binary')
50
+ .map(f => f.value);
51
+ }, [appliedFilters]);
52
+
53
+ console.log('currentBinaryFilters', currentBinaryFilters);
47
54
 
48
55
  const mappingsList = useMappingList(mappings);
49
56
 
@@ -80,8 +87,7 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
80
87
  <div className="my-4 flex w-full flex-wrap justify-start column-gap-2">
81
88
  {stackColorArray.map(([feature, color]) => {
82
89
  const filteringAllowed = feature !== EVERYTHING_ELSE;
83
- const isHighlighted =
84
- currentSearchString !== undefined ? currentSearchString.includes(feature) : false;
90
+ const isHighlighted = currentBinaryFilters.includes(feature);
85
91
  return (
86
92
  <div
87
93
  key={feature}
@@ -97,10 +103,8 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
97
103
  return;
98
104
  }
99
105
 
100
- // Check if the current search string is defined and an array
101
- const updatedSearchString = [...currentSearchString, feature]; // If array, append the feature
102
-
103
- setSearchString(updatedSearchString);
106
+ // Remove the exclude filter for this binary
107
+ removeExcludeBinary(feature);
104
108
  }}
105
109
  >
106
110
  <div className="flex w-11/12 items-center justify-start">
@@ -119,8 +123,8 @@ const ColorStackLegend = ({mappings, compareMode = false, loading}: Props): Reac
119
123
  <Icon
120
124
  icon="radix-icons:cross-circled"
121
125
  onClick={e => {
122
- // remove the current feature from the search string array of strings
123
- setSearchString(currentSearchString.filter((f: string) => f !== feature));
126
+ // Find and remove the filter for this binary
127
+ excludeBinary(feature);
124
128
  e.stopPropagation();
125
129
  }}
126
130
  />
@@ -44,8 +44,6 @@ interface GetDashboardItemProps {
44
44
  setNewCurPath: (path: string[]) => void;
45
45
  curPathArrow: CurrentPathFrame[];
46
46
  setNewCurPathArrow: (path: CurrentPathFrame[]) => void;
47
- currentSearchString?: string;
48
- setSearchString?: (value: string) => void;
49
47
  perf?: {
50
48
  onRender?: ProfilerOnRenderCallback;
51
49
  };
@@ -65,8 +63,6 @@ export const getDashboardItem = ({
65
63
  filtered,
66
64
  curPathArrow,
67
65
  setNewCurPathArrow,
68
- currentSearchString,
69
- setSearchString,
70
66
  perf,
71
67
  queryClient,
72
68
  }: GetDashboardItemProps): JSX.Element => {
@@ -138,8 +134,6 @@ export const getDashboardItem = ({
138
134
  data={topTableData.arrow?.record}
139
135
  unit={topTableData.unit}
140
136
  profileType={profileSource?.ProfileType()}
141
- currentSearchString={currentSearchString}
142
- setSearchString={setSearchString}
143
137
  isHalfScreen={isHalfScreen}
144
138
  metadataMappingFiles={flamegraphData.metadataMappingFiles}
145
139
  />
@@ -28,7 +28,7 @@ interface Props {
28
28
 
29
29
  const GroupByLabelsDropdown = ({labels, groupBy, setGroupByLabels}: Props): JSX.Element => {
30
30
  return (
31
- <div>
31
+ <div className="flex flex-col">
32
32
  <div className="flex items-center justify-between">
33
33
  <label className="text-sm">Group by</label>
34
34
  </div>
@@ -40,7 +40,7 @@ const GroupByLabelsDropdown = ({labels, groupBy, setGroupByLabels}: Props): JSX.
40
40
  defaultValue={undefined}
41
41
  name="labels"
42
42
  options={labels.map(label => ({label, value: `${FIELD_LABELS}.${label}`}))}
43
- className="parca-select-container text-sm w-full rounded-md bg-white"
43
+ className="parca-select-container text-sm rounded-md bg-white"
44
44
  classNamePrefix="parca-select"
45
45
  value={groupBy
46
46
  .filter(l => l.startsWith(FIELD_LABELS))
@@ -66,12 +66,25 @@ const GroupByLabelsDropdown = ({labels, groupBy, setGroupByLabels}: Props): JSX.
66
66
  borderRight: '1px solid #e2e8f0',
67
67
  borderLeft: '1px solid #e2e8f0',
68
68
  borderTop: '1px solid #e2e8f0',
69
+ minWidth: '156px',
70
+ width: 'max-content',
71
+ minHeight: '38px',
69
72
  ':hover': {
70
73
  borderColor: '#e2e8f0',
71
74
  borderBottomLeftRadius: 0,
72
75
  borderBottomRightRadius: 0,
73
76
  },
74
77
  }),
78
+ valueContainer: provided => ({
79
+ ...provided,
80
+ flexWrap: 'nowrap',
81
+ overflowX: 'auto',
82
+ padding: '2px 8px',
83
+ }),
84
+ multiValue: provided => ({
85
+ ...provided,
86
+ flex: '0 0 auto',
87
+ }),
75
88
  option: provided => ({
76
89
  ...provided,
77
90
  ':hover': {
@@ -22,7 +22,7 @@ const InvertCallStack = (): JSX.Element => {
22
22
  return (
23
23
  <Button
24
24
  variant="neutral"
25
- className="flex items-center gap-2"
25
+ className="flex items-center gap-2 whitespace-nowrap"
26
26
  onClick={() => setInvertStack(isInvert ? '' : 'true')}
27
27
  id="h-invert-call-stack"
28
28
  >