@parca/profile 0.16.373 → 0.16.375

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 (42) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/GraphTooltipArrow/Content.js +1 -1
  3. package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +1 -1
  4. package/dist/ProfileIcicleGraph/IcicleGraph/useColoredGraph.js +1 -1
  5. package/dist/ProfileIcicleGraph/IcicleGraph/utils.d.ts +1 -1
  6. package/dist/ProfileIcicleGraph/IcicleGraph/utils.js +1 -5
  7. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.js +23 -9
  8. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.d.ts +2 -1
  9. package/dist/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +3 -2
  10. package/dist/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.js +0 -1
  11. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.d.ts +1 -0
  12. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +29 -47
  13. package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.d.ts +1 -2
  14. package/dist/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.js +2 -7
  15. package/dist/ProfileIcicleGraph/IcicleGraphArrow/utils.js +0 -3
  16. package/dist/ProfileIcicleGraph/index.d.ts +2 -1
  17. package/dist/ProfileIcicleGraph/index.js +26 -22
  18. package/dist/ProfileSource.js +2 -0
  19. package/dist/ProfileView/index.d.ts +2 -0
  20. package/dist/ProfileView/index.js +2 -2
  21. package/dist/ProfileViewWithData.js +17 -10
  22. package/dist/useQuery.d.ts +1 -3
  23. package/dist/useQuery.js +21 -8
  24. package/package.json +7 -7
  25. package/src/GraphTooltipArrow/Content.tsx +1 -5
  26. package/src/GraphTooltipArrow/DockedGraphTooltip/index.tsx +1 -1
  27. package/src/ProfileIcicleGraph/IcicleGraph/useColoredGraph.ts +1 -1
  28. package/src/ProfileIcicleGraph/IcicleGraph/utils.ts +1 -7
  29. package/src/ProfileIcicleGraph/IcicleGraphArrow/ColorStackLegend.tsx +26 -9
  30. package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +21 -1
  31. package/src/ProfileIcicleGraph/IcicleGraphArrow/IcicleGraphNodes.tsx +0 -1
  32. package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +39 -48
  33. package/src/ProfileIcicleGraph/IcicleGraphArrow/useNodeColor.ts +1 -8
  34. package/src/ProfileIcicleGraph/IcicleGraphArrow/utils.ts +0 -5
  35. package/src/ProfileIcicleGraph/index.tsx +65 -50
  36. package/src/ProfileSource.tsx +2 -0
  37. package/src/ProfileView/index.tsx +4 -1
  38. package/src/ProfileViewWithData.tsx +26 -10
  39. package/src/useQuery.tsx +22 -11
  40. package/dist/ProfileIcicleGraph/ActionButtons/RuntimeFilterDropdown.d.ts +0 -9
  41. package/dist/ProfileIcicleGraph/ActionButtons/RuntimeFilterDropdown.js +0 -23
  42. package/src/ProfileIcicleGraph/ActionButtons/RuntimeFilterDropdown.tsx +0 -123
@@ -11,7 +11,7 @@
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} from 'react';
14
+ import React, {useCallback, useEffect, useMemo, useState} from 'react';
15
15
 
16
16
  import {Icon} from '@iconify/react';
17
17
  import {AnimatePresence, motion} from 'framer-motion';
@@ -32,7 +32,6 @@ import {capitalizeOnlyFirstLetter, divide, type NavigateFunction} from '@parca/u
32
32
  import {useProfileViewContext} from '../ProfileView/ProfileViewContext';
33
33
  import DiffLegend from '../components/DiffLegend';
34
34
  import GroupByDropdown from './ActionButtons/GroupByDropdown';
35
- import RuntimeFilterDropdown from './ActionButtons/RuntimeFilterDropdown';
36
35
  import SortBySelect from './ActionButtons/SortBySelect';
37
36
  import IcicleGraph from './IcicleGraph';
38
37
  import IcicleGraphArrow, {FIELD_FUNCTION_NAME} from './IcicleGraphArrow';
@@ -55,6 +54,7 @@ interface ProfileIcicleGraphProps {
55
54
  setActionButtons?: (buttons: React.JSX.Element) => void;
56
55
  error?: any;
57
56
  isHalfScreen: boolean;
57
+ mappings?: string[];
58
58
  }
59
59
 
60
60
  const ErrorContent = ({errorMessage}: {errorMessage: string}): JSX.Element => {
@@ -72,6 +72,10 @@ const ShowHideLegendButton = ({
72
72
  param: 'color_stack_legend',
73
73
  navigateTo,
74
74
  });
75
+ const [binaryFrameFilter, setBinaryFrameFilter] = useURLState({
76
+ param: 'binary_frame_filter',
77
+ navigateTo,
78
+ });
75
79
 
76
80
  const {compareMode} = useProfileViewContext();
77
81
 
@@ -88,28 +92,56 @@ const ShowHideLegendButton = ({
88
92
  [setStoreColorStackLegend]
89
93
  );
90
94
 
95
+ const resetLegend = (): void => {
96
+ setBinaryFrameFilter([]);
97
+ };
98
+
91
99
  return (
92
100
  <>
93
101
  {colorProfileName === 'default' || compareMode ? null : (
94
102
  <>
95
103
  {isHalfScreen ? (
96
- <IconButton
97
- className="rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]"
98
- icon={isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye'}
99
- toolTipText={isColorStackLegendEnabled ? 'Hide legend' : 'Show legend'}
100
- onClick={() => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true')}
101
- id="h-show-legend-button"
102
- />
104
+ <>
105
+ <IconButton
106
+ className="rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]"
107
+ icon={isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye'}
108
+ toolTipText={isColorStackLegendEnabled ? 'Hide legend' : 'Show legend'}
109
+ onClick={() => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true')}
110
+ id="h-show-legend-button"
111
+ />
112
+ {binaryFrameFilter !== undefined && binaryFrameFilter.length > 0 && (
113
+ <IconButton
114
+ className="rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]"
115
+ icon="system-uicons:reset"
116
+ toolTipText="Reset the legend selection"
117
+ onClick={() => resetLegend()}
118
+ id="h-reset-legend-button"
119
+ />
120
+ )}
121
+ </>
103
122
  ) : (
104
- <Button
105
- className="gap-2 w-max"
106
- variant="neutral"
107
- onClick={() => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true')}
108
- id="h-show-legend-button"
109
- >
110
- {isColorStackLegendEnabled ? 'Hide legend' : 'Show legend'}
111
- <Icon icon={isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye'} width={20} />
112
- </Button>
123
+ <>
124
+ <Button
125
+ className="gap-2 w-max"
126
+ variant="neutral"
127
+ onClick={() => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true')}
128
+ id="h-show-legend-button"
129
+ >
130
+ {isColorStackLegendEnabled ? 'Hide legend' : 'Show legend'}
131
+ <Icon icon={isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye'} width={20} />
132
+ </Button>
133
+ {binaryFrameFilter !== undefined && binaryFrameFilter.length > 0 && (
134
+ <Button
135
+ className="gap-2 w-max"
136
+ variant="neutral"
137
+ onClick={() => resetLegend()}
138
+ id="h-reset-legend-button"
139
+ >
140
+ Reset Legend
141
+ <Icon icon="system-uicons:reset" width={20} />
142
+ </Button>
143
+ )}
144
+ </>
113
145
  )}
114
146
  </>
115
147
  )}
@@ -155,21 +187,6 @@ const GroupAndSortActionButtons = ({navigateTo}: {navigateTo?: NavigateFunction}
155
187
  [groupBy, setGroupBy]
156
188
  );
157
189
 
158
- const [showRuntimeRubyStr, setShowRuntimeRuby] = useURLState({
159
- param: 'show_runtime_ruby',
160
- navigateTo,
161
- });
162
-
163
- const [showRuntimePythonStr, setShowRuntimePython] = useURLState({
164
- param: 'show_runtime_python',
165
- navigateTo,
166
- });
167
-
168
- const [showInterpretedOnlyStr, setShowInterpretedOnly] = useURLState({
169
- param: 'show_interpreted_only',
170
- navigateTo,
171
- });
172
-
173
190
  return (
174
191
  <>
175
192
  <GroupByDropdown groupBy={groupBy} toggleGroupBy={toggleGroupBy} />
@@ -178,20 +195,6 @@ const GroupAndSortActionButtons = ({navigateTo}: {navigateTo?: NavigateFunction}
178
195
  sortBy={storeSortBy as string}
179
196
  setSortBy={setStoreSortBy}
180
197
  />
181
- <RuntimeFilterDropdown
182
- showRuntimeRuby={showRuntimeRubyStr === 'true'}
183
- toggleShowRuntimeRuby={() =>
184
- setShowRuntimeRuby(showRuntimeRubyStr === 'true' ? 'false' : 'true')
185
- }
186
- showRuntimePython={showRuntimePythonStr === 'true'}
187
- toggleShowRuntimePython={() =>
188
- setShowRuntimePython(showRuntimePythonStr === 'true' ? 'false' : 'true')
189
- }
190
- showInterpretedOnly={showInterpretedOnlyStr === 'true'}
191
- toggleShowInterpretedOnly={() =>
192
- setShowInterpretedOnly(showInterpretedOnlyStr === 'true' ? 'false' : 'true')
193
- }
194
- />
195
198
  </>
196
199
  );
197
200
  };
@@ -210,9 +213,11 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
210
213
  error,
211
214
  width,
212
215
  isHalfScreen,
216
+ mappings,
213
217
  }: ProfileIcicleGraphProps): JSX.Element {
214
218
  const {onError, authenticationErrorMessage, isDarkMode} = useParcaContext();
215
219
  const {compareMode} = useProfileViewContext();
220
+ const [isLoading, setIsLoading] = useState<boolean>(true);
216
221
 
217
222
  const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState({
218
223
  param: 'sort_by',
@@ -257,7 +262,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
257
262
  }, [graph, arrow, filtered, total]);
258
263
 
259
264
  useEffect(() => {
260
- if (loading && setActionButtons !== undefined) {
265
+ if (isLoading && setActionButtons !== undefined) {
261
266
  setActionButtons(<IcicleActionButtonPlaceholder isHalfScreen={isHalfScreen} />);
262
267
  return;
263
268
  }
@@ -270,7 +275,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
270
275
  <div className="flex w-full justify-end gap-2 pb-2">
271
276
  <div className="ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end">
272
277
  {arrow !== undefined && <GroupAndSortActionButtons navigateTo={navigateTo} />}
273
- {isHalfScreen ? (
278
+ {arrow !== undefined && isHalfScreen ? (
274
279
  <IconButton
275
280
  icon={isInvert ? 'ph:sort-ascending' : 'ph:sort-descending'}
276
281
  toolTipText={isInvert ? 'Original Call Stack' : 'Invert Call Stack'}
@@ -320,9 +325,18 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
320
325
  setActionButtons,
321
326
  loading,
322
327
  isHalfScreen,
328
+ isLoading,
323
329
  ]);
324
330
 
325
- if (loading) {
331
+ useEffect(() => {
332
+ if (!loading && (arrow !== undefined || graph !== undefined)) {
333
+ setIsLoading(false);
334
+ } else {
335
+ setIsLoading(true);
336
+ }
337
+ }, [loading, arrow, graph]);
338
+
339
+ if (isLoading) {
326
340
  return (
327
341
  <div className="h-auto overflow-clip">
328
342
  <IcicleGraphSkeleton isHalfScreen={isHalfScreen} isDarkMode={isDarkMode} />
@@ -384,6 +398,7 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({
384
398
  profileType={profileType}
385
399
  navigateTo={navigateTo}
386
400
  sortBy={storeSortBy as string}
401
+ mappings={mappings}
387
402
  />
388
403
  )}
389
404
  </div>
@@ -166,6 +166,7 @@ export class ProfileDiffSource implements ProfileSource {
166
166
  reportType: QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED,
167
167
  mode: QueryRequest_Mode.DIFF,
168
168
  filterQuery: this.filterQuery,
169
+ filter: [],
169
170
  };
170
171
  }
171
172
 
@@ -233,6 +234,7 @@ export class MergedProfileSource implements ProfileSource {
233
234
  reportType: QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED,
234
235
  mode: QueryRequest_Mode.MERGE,
235
236
  filterQuery: this.filterQuery,
237
+ filter: [],
236
238
  };
237
239
  }
238
240
 
@@ -67,6 +67,8 @@ export interface FlamegraphData {
67
67
  total?: bigint;
68
68
  filtered?: bigint;
69
69
  error?: any;
70
+ mappings?: string[];
71
+ mappingsLoading: boolean;
70
72
  }
71
73
 
72
74
  export interface TopTableData {
@@ -238,7 +240,7 @@ export const ProfileView = ({
238
240
  filtered={filtered}
239
241
  profileType={profileSource?.ProfileType()}
240
242
  navigateTo={navigateTo}
241
- loading={flamegraphData.loading}
243
+ loading={flamegraphData.loading && flamegraphData.mappingsLoading}
242
244
  setActionButtons={setActionButtons}
243
245
  error={flamegraphData.error}
244
246
  isHalfScreen={isHalfScreen}
@@ -249,6 +251,7 @@ export const ProfileView = ({
249
251
  : dimensions.width - 16
250
252
  : 0
251
253
  }
254
+ mappings={flamegraphData.mappings}
252
255
  />
253
256
  </ConditionalWrapper>
254
257
  );
@@ -43,14 +43,14 @@ export const ProfileViewWithData = ({
43
43
  ];
44
44
  const [groupBy = [FIELD_FUNCTION_NAME]] = useURLState({param: 'group_by', navigateTo});
45
45
 
46
- const [showRuntimeRubyStr] = useURLState({param: 'show_runtime_ruby', navigateTo});
47
- const showRuntimeRuby = showRuntimeRubyStr === 'true';
48
- const [showRuntimePythonStr] = useURLState({param: 'show_runtime_python', navigateTo});
49
- const showRuntimePython = showRuntimePythonStr === 'true';
50
- const [showInterpretedOnlyStr] = useURLState({param: 'show_interpreted_only', navigateTo});
51
- const showInterpretedOnly = showInterpretedOnlyStr === 'true';
52
46
  const [invertStack] = useURLState({param: 'invert_call_stack', navigateTo});
53
47
  const invertCallStack = invertStack === 'true';
48
+ const [binaryFrameFilterStr] = useURLState({param: 'binary_frame_filter', navigateTo});
49
+
50
+ const binaryFrameFilter: string[] =
51
+ typeof binaryFrameFilterStr === 'string'
52
+ ? binaryFrameFilterStr.split(',')
53
+ : binaryFrameFilterStr;
54
54
 
55
55
  const [pprofDownloading, setPprofDownloading] = useState<boolean>(false);
56
56
 
@@ -74,12 +74,23 @@ export const ProfileViewWithData = ({
74
74
  skip: !dashboardItems.includes('icicle'),
75
75
  nodeTrimThreshold,
76
76
  groupBy: groupByParam,
77
- showRuntimeRuby,
78
- showRuntimePython,
79
- showInterpretedOnly,
80
77
  invertCallStack,
78
+ binaryFrameFilter,
81
79
  });
82
80
 
81
+ const {isLoading: profilemetadataLoading, response: profilemetadataResponse} = useQuery(
82
+ queryClient,
83
+ profileSource,
84
+ QueryRequest_ReportType.PROFILE_METADATA,
85
+ {
86
+ skip: !dashboardItems.includes('icicle'),
87
+ nodeTrimThreshold,
88
+ groupBy: groupByParam,
89
+ invertCallStack,
90
+ binaryFrameFilter: undefined,
91
+ }
92
+ );
93
+
83
94
  const {perf} = useParcaContext();
84
95
 
85
96
  const {
@@ -178,7 +189,7 @@ export const ProfileViewWithData = ({
178
189
  total={total}
179
190
  filtered={filtered}
180
191
  flamegraphData={{
181
- loading: flamegraphLoading,
192
+ loading: flamegraphLoading && profilemetadataLoading,
182
193
  data:
183
194
  flamegraphResponse?.report.oneofKind === 'flamegraph'
184
195
  ? flamegraphResponse?.report?.flamegraph
@@ -190,6 +201,11 @@ export const ProfileViewWithData = ({
190
201
  total: BigInt(flamegraphResponse?.total ?? '0'),
191
202
  filtered: BigInt(flamegraphResponse?.filtered ?? '0'),
192
203
  error: flamegraphError,
204
+ mappings:
205
+ profilemetadataResponse?.report.oneofKind === 'profileMetadata'
206
+ ? profilemetadataResponse?.report?.profileMetadata?.mappingFiles
207
+ : undefined,
208
+ mappingsLoading: profilemetadataLoading,
193
209
  }}
194
210
  topTableData={{
195
211
  loading: tableLoading,
package/src/useQuery.tsx CHANGED
@@ -32,10 +32,8 @@ interface UseQueryOptions {
32
32
  sourceBuildID?: string;
33
33
  sourceFilename?: string;
34
34
  sourceOnly?: boolean;
35
- showRuntimeRuby?: boolean;
36
- showRuntimePython?: boolean;
37
- showInterpretedOnly?: boolean;
38
35
  invertCallStack?: boolean;
36
+ binaryFrameFilter?: string[];
39
37
  }
40
38
 
41
39
  export const useQuery = (
@@ -56,10 +54,8 @@ export const useQuery = (
56
54
  options?.sourceBuildID,
57
55
  options?.sourceOnly,
58
56
  options?.sourceOnly === true ? '' : options?.sourceFilename,
59
- options?.showRuntimeRuby ?? false,
60
- options?.showRuntimePython ?? false,
61
- options?.showInterpretedOnly ?? false,
62
57
  options?.invertCallStack ?? false,
58
+ options?.binaryFrameFilter ?? '',
63
59
  ],
64
60
  queryFn: async () => {
65
61
  const req = profileSource.QueryRequest();
@@ -75,13 +71,28 @@ export const useQuery = (
75
71
  sourceOnly: options?.sourceOnly ?? false,
76
72
  };
77
73
  }
78
- req.runtimeFilter = {
79
- showRuby: options?.showRuntimeRuby ?? false,
80
- showPython: options?.showRuntimePython ?? false,
81
- showInterpretedOnly: options?.showInterpretedOnly ?? false,
82
- };
83
74
  req.invertCallStack = options?.invertCallStack ?? false;
84
75
 
76
+ if (options?.binaryFrameFilter !== undefined && options?.binaryFrameFilter.length > 0) {
77
+ req.filter = [
78
+ {
79
+ filter: {
80
+ oneofKind: 'frameFilter',
81
+ frameFilter: {
82
+ filter: {
83
+ oneofKind: 'binaryFrameFilter',
84
+ binaryFrameFilter: {
85
+ includeBinaries: options?.binaryFrameFilter ?? [],
86
+ },
87
+ },
88
+ },
89
+ },
90
+ },
91
+ ];
92
+ } else {
93
+ req.filter = [];
94
+ }
95
+
85
96
  try {
86
97
  const {response} = await client.query(req, {meta: metadata});
87
98
  return response;
@@ -1,9 +0,0 @@
1
- declare const RuntimeFilterDropdown: ({ showRuntimeRuby, toggleShowRuntimeRuby, showRuntimePython, toggleShowRuntimePython, showInterpretedOnly, toggleShowInterpretedOnly, }: {
2
- showRuntimeRuby: boolean;
3
- toggleShowRuntimeRuby: () => void;
4
- showRuntimePython: boolean;
5
- toggleShowRuntimePython: () => void;
6
- showInterpretedOnly: boolean;
7
- toggleShowInterpretedOnly: () => void;
8
- }) => React.JSX.Element;
9
- export default RuntimeFilterDropdown;
@@ -1,23 +0,0 @@
1
- import { 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 { Fragment } from 'react';
15
- import { Menu, Transition } from '@headlessui/react';
16
- import { Icon } from '@iconify/react';
17
- const RuntimeToggle = ({ id, state, toggle, label, description, }) => {
18
- return (_jsxs("div", { className: "relative flex items-start", children: [_jsx("div", { className: "flex h-6 items-center", children: _jsx("input", { id: id, name: id, type: "checkbox", className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", checked: state, onChange: () => toggle() }) }), _jsxs("div", { className: "ml-3 text-sm leading-6", children: [_jsx("label", { htmlFor: id, className: "font-medium text-gray-900 dark:text-gray-200", children: label }), _jsx("p", { className: "text-gray-500 dark:text-gray-400", children: description })] })] }, id));
19
- };
20
- const RuntimeFilterDropdown = ({ showRuntimeRuby, toggleShowRuntimeRuby, showRuntimePython, toggleShowRuntimePython, showInterpretedOnly, toggleShowInterpretedOnly, }) => {
21
- return (_jsxs("div", { children: [_jsx("label", { className: "text-sm", children: "Runtimes" }), _jsxs(Menu, { as: "div", className: "relative text-left", id: "h-runtimes-filter", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-[1.7rem] text-left text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 sm:text-sm", children: [_jsx("span", { className: "block overflow-x-hidden text-ellipsis", children: "Runtimes" }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }) }), _jsx(Transition, { as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx(Menu.Items, { className: "absolute left-0 z-10 mt-1 min-w-[400px] overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm", children: _jsx("div", { className: "p-4", children: _jsx("fieldset", { children: _jsxs("div", { className: "space-y-5", children: [_jsx(RuntimeToggle, { id: "show-runtime-ruby", state: showRuntimeRuby, toggle: toggleShowRuntimeRuby, label: "Ruby", description: "Show Ruby runtime functions." }), _jsx(RuntimeToggle, { id: "show-runtime-python", state: showRuntimePython, toggle: toggleShowRuntimePython, label: "Python", description: "Show Python runtime functions." }), _jsx(RuntimeToggle, { id: "show-interpreted-only", state: showInterpretedOnly, toggle: toggleShowInterpretedOnly, label: "Interpreted Only", description: "Show only interpreted functions." })] }) }) }) }) })] })] }));
22
- };
23
- export default RuntimeFilterDropdown;
@@ -1,123 +0,0 @@
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
-
14
- import {Fragment} from 'react';
15
-
16
- import {Menu, Transition} from '@headlessui/react';
17
- import {Icon} from '@iconify/react';
18
-
19
- const RuntimeToggle = ({
20
- id,
21
- state,
22
- toggle,
23
- label,
24
- description,
25
- }: {
26
- id: string;
27
- state: boolean;
28
- toggle: () => void;
29
- label: string;
30
- description: string;
31
- }): JSX.Element => {
32
- return (
33
- <div key={id} className="relative flex items-start">
34
- <div className="flex h-6 items-center">
35
- <input
36
- id={id}
37
- name={id}
38
- type="checkbox"
39
- className="h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600"
40
- checked={state}
41
- onChange={() => toggle()}
42
- />
43
- </div>
44
- <div className="ml-3 text-sm leading-6">
45
- <label htmlFor={id} className="font-medium text-gray-900 dark:text-gray-200">
46
- {label}
47
- </label>
48
- <p className="text-gray-500 dark:text-gray-400">{description}</p>
49
- </div>
50
- </div>
51
- );
52
- };
53
-
54
- const RuntimeFilterDropdown = ({
55
- showRuntimeRuby,
56
- toggleShowRuntimeRuby,
57
- showRuntimePython,
58
- toggleShowRuntimePython,
59
- showInterpretedOnly,
60
- toggleShowInterpretedOnly,
61
- }: {
62
- showRuntimeRuby: boolean;
63
- toggleShowRuntimeRuby: () => void;
64
- showRuntimePython: boolean;
65
- toggleShowRuntimePython: () => void;
66
- showInterpretedOnly: boolean;
67
- toggleShowInterpretedOnly: () => void;
68
- }): React.JSX.Element => {
69
- return (
70
- <div>
71
- <label className="text-sm">Runtimes</label>
72
- <Menu as="div" className="relative text-left" id="h-runtimes-filter">
73
- <div>
74
- <Menu.Button className="relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-[1.7rem] text-left text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 sm:text-sm">
75
- <span className="block overflow-x-hidden text-ellipsis">Runtimes</span>
76
- <span className="pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2 text-gray-400">
77
- <Icon icon="heroicons:chevron-down-20-solid" aria-hidden="true" />
78
- </span>
79
- </Menu.Button>
80
- </div>
81
-
82
- <Transition
83
- as={Fragment}
84
- leave="transition ease-in duration-100"
85
- leaveFrom="opacity-100"
86
- leaveTo="opacity-0"
87
- >
88
- <Menu.Items className="absolute left-0 z-10 mt-1 min-w-[400px] overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm">
89
- <div className="p-4">
90
- <fieldset>
91
- <div className="space-y-5">
92
- <RuntimeToggle
93
- id="show-runtime-ruby"
94
- state={showRuntimeRuby}
95
- toggle={toggleShowRuntimeRuby}
96
- label="Ruby"
97
- description="Show Ruby runtime functions."
98
- />
99
- <RuntimeToggle
100
- id="show-runtime-python"
101
- state={showRuntimePython}
102
- toggle={toggleShowRuntimePython}
103
- label="Python"
104
- description="Show Python runtime functions."
105
- />
106
- <RuntimeToggle
107
- id="show-interpreted-only"
108
- state={showInterpretedOnly}
109
- toggle={toggleShowInterpretedOnly}
110
- label="Interpreted Only"
111
- description="Show only interpreted functions."
112
- />
113
- </div>
114
- </fieldset>
115
- </div>
116
- </Menu.Items>
117
- </Transition>
118
- </Menu>
119
- </div>
120
- );
121
- };
122
-
123
- export default RuntimeFilterDropdown;