@parca/profile 0.16.369 → 0.16.370
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 +4 -0
- package/dist/MetricsGraph/index.js +3 -2
- package/dist/ProfileIcicleGraph/GroupByDropdown.d.ts +5 -0
- package/dist/ProfileIcicleGraph/GroupByDropdown.js +11 -0
- package/dist/ProfileIcicleGraph/RuntimeFilterDropdown.d.ts +9 -0
- package/dist/ProfileIcicleGraph/RuntimeFilterDropdown.js +11 -0
- package/dist/ProfileIcicleGraph/SortBySelect.d.ts +6 -0
- package/dist/ProfileIcicleGraph/SortBySelect.js +31 -0
- package/dist/ProfileSelector/index.js +1 -1
- package/dist/ProfileTypeSelector/index.d.ts +2 -1
- package/dist/ProfileTypeSelector/index.js +2 -2
- package/dist/QueryBrowser/index.d.ts +12 -0
- package/dist/QueryBrowser/index.js +51 -0
- package/package.json +6 -6
- package/src/MetricsGraph/index.tsx +3 -2
- package/src/ProfileSelector/index.tsx +1 -0
- package/src/ProfileTypeSelector/index.tsx +3 -0
- package/src/ProfileIcicleGraph/benchmarks/benchdata/parca-10m.json +0 -1
- package/src/ProfileIcicleGraph/benchmarks/benchdata/parca-1m.json +0 -1
- package/src/ProfileIcicleGraph/benchmarks/benchdata/parca-20m.json +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.16.370](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.369...@parca/profile@0.16.370) (2024-05-14)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
6
10
|
## [0.16.369](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.368...@parca/profile@0.16.369) (2024-05-14)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
-
import { Fragment, useCallback, useMemo, useRef, useState } from 'react';
|
|
14
|
+
import { Fragment, useCallback, useId, useMemo, useRef, useState } from 'react';
|
|
15
15
|
import * as d3 from 'd3';
|
|
16
16
|
import { pointer } from 'd3-selection';
|
|
17
17
|
import throttle from 'lodash.throttle';
|
|
@@ -45,6 +45,7 @@ export const RawMetricsGraph = ({ data, from, to, profile, onSampleClick, addLab
|
|
|
45
45
|
const [pos, setPos] = useState([0, 0]);
|
|
46
46
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState(false);
|
|
47
47
|
const metricPointRef = useRef(null);
|
|
48
|
+
const idForContextMenu = useId();
|
|
48
49
|
// the time of the selected point is the start of the merge window
|
|
49
50
|
const time = parseFloat(profile?.HistoryParams().merge_from);
|
|
50
51
|
if (width === undefined || width == null) {
|
|
@@ -228,7 +229,7 @@ export const RawMetricsGraph = ({ data, from, to, profile, onSampleClick, addLab
|
|
|
228
229
|
};
|
|
229
230
|
};
|
|
230
231
|
const selected = findSelectedProfile();
|
|
231
|
-
const MENU_ID =
|
|
232
|
+
const MENU_ID = `metrics-context-menu-${idForContextMenu}`;
|
|
232
233
|
const { show } = useContextMenu({
|
|
233
234
|
id: MENU_ID,
|
|
234
235
|
});
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Menu, Transition } from '@headlessui/react';
|
|
3
|
+
const GroupByDropdown = ({ groupBy, toggleGroupBy, }) => {
|
|
4
|
+
const label = groupBy.length === 0
|
|
5
|
+
? 'Nothing'
|
|
6
|
+
: groupBy.length === 1
|
|
7
|
+
? groupByOptions.find(option => option.value === groupBy[0])?.label
|
|
8
|
+
: 'Multiple';
|
|
9
|
+
return (_jsxs("div", { children: [_jsx("label", { className: "text-sm", children: "Group" }), _jsxs(Menu, { as: "div", className: "relative text-left", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-10 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: label }), _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: _jsx("div", { className: "space-y-5", children: groupByOptions.map(({ value, label, description, disabled }) => (_jsxs("div", { className: "relative flex items-start", children: [_jsx("div", { className: "flex h-6 items-center", children: _jsx("input", { id: value, name: value, type: "checkbox", disabled: disabled, className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", checked: groupBy.includes(value), onChange: () => toggleGroupBy(value) }) }), _jsxs("div", { className: "ml-3 text-sm leading-6", children: [_jsx("label", { htmlFor: value, className: "font-medium text-gray-900 dark:text-gray-200", children: label }), _jsx("p", { className: "text-gray-500 dark:text-gray-400", children: description })] })] }, value))) }) }) }) }) })] })] }));
|
|
10
|
+
};
|
|
11
|
+
export default GroupByDropdown;
|
|
@@ -0,0 +1,9 @@
|
|
|
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;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Fragment } from 'react';
|
|
3
|
+
import { Menu, Transition } from '@headlessui/react';
|
|
4
|
+
import { Icon } from '@iconify/react';
|
|
5
|
+
const RuntimeToggle = ({ id, state, toggle, label, description, }) => {
|
|
6
|
+
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));
|
|
7
|
+
};
|
|
8
|
+
const RuntimeFilterDropdown = ({ showRuntimeRuby, toggleShowRuntimeRuby, showRuntimePython, toggleShowRuntimePython, showInterpretedOnly, toggleShowInterpretedOnly, }) => {
|
|
9
|
+
return (_jsxs("div", { children: [_jsx("label", { className: "text-sm", children: "Runtimes" }), _jsxs(Menu, { as: "div", className: "relative text-left", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-10 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." })] }) }) }) }) })] })] }));
|
|
10
|
+
};
|
|
11
|
+
export default RuntimeFilterDropdown;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { FIELD_CUMULATIVE, FIELD_DIFF, FIELD_FUNCTION_NAME, } from './IcicleGraphArrow';
|
|
3
|
+
const SortBySelect = ({ sortBy, setSortBy, compareMode, }) => {
|
|
4
|
+
return (_jsxs("div", { children: [_jsx("label", { className: "text-sm", children: "Sort" }), _jsx(Select, { items: [
|
|
5
|
+
{
|
|
6
|
+
key: FIELD_FUNCTION_NAME,
|
|
7
|
+
disabled: false,
|
|
8
|
+
element: {
|
|
9
|
+
active: _jsx(_Fragment, { children: "Function" }),
|
|
10
|
+
expanded: (_jsx(_Fragment, { children: _jsx("span", { children: "Function" }) })),
|
|
11
|
+
},
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
key: FIELD_CUMULATIVE,
|
|
15
|
+
disabled: false,
|
|
16
|
+
element: {
|
|
17
|
+
active: _jsx(_Fragment, { children: "Cumulative" }),
|
|
18
|
+
expanded: (_jsx(_Fragment, { children: _jsx("span", { children: "Cumulative" }) })),
|
|
19
|
+
},
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
key: FIELD_DIFF,
|
|
23
|
+
disabled: !compareMode,
|
|
24
|
+
element: {
|
|
25
|
+
active: _jsx(_Fragment, { children: "Diff" }),
|
|
26
|
+
expanded: (_jsx(_Fragment, { children: _jsx("span", { children: "Diff" }) })),
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
], selectedKey: sortBy, onSelection: key => setSortBy(key), placeholder: 'Sort By', primary: false, disabled: false })] }));
|
|
30
|
+
};
|
|
31
|
+
export default SortBySelect;
|
|
@@ -143,7 +143,7 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
|
|
|
143
143
|
queryExpressionString === '' ||
|
|
144
144
|
queryExpressionString === '{}';
|
|
145
145
|
const compareDisabled = selectedProfileName === '' || querySelection.expression === undefined;
|
|
146
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex gap-2", children: [_jsxs("div", { className: "flex w-full flex-wrap content-start items-center justify-between gap-2", children: [_jsxs("div", { className: "pb-6", children: [_jsx("label", { className: "text-xs", children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error })] }), _jsxs("div", { className: "w-full flex-1 pb-6", children: [_jsxs("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: [_jsx("label", { className: "text-xs", children: "Query" }), (query.matchers.length > 0 || query.inputMatcherString.length > 0) &&
|
|
146
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex gap-2", children: [_jsxs("div", { className: "flex w-full flex-wrap content-start items-center justify-between gap-2", children: [_jsxs("div", { className: "pb-6", children: [_jsx("label", { className: "text-xs", children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error, disabled: viewComponent?.disableProfileTypesDropdown })] }), _jsxs("div", { className: "w-full flex-1 pb-6", children: [_jsxs("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: [_jsx("label", { className: "text-xs", children: "Query" }), (query.matchers.length > 0 || query.inputMatcherString.length > 0) &&
|
|
147
147
|
viewComponent !== undefined && _jsx("div", { children: viewComponent?.createViewComponent })] }), _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query })] }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsxs(ButtonGroup, { children: [!searchDisabled && (_jsx(_Fragment, { children: !comparing && (_jsx(CompareButton, { disabled: compareDisabled, onClick: handleCompareClick })) })), _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
|
|
148
148
|
e.preventDefault();
|
|
149
149
|
setQueryExpression(true);
|
|
@@ -21,6 +21,7 @@ interface Props {
|
|
|
21
21
|
selectedKey: string | undefined;
|
|
22
22
|
flexibleKnownProfilesDetection?: boolean;
|
|
23
23
|
onSelection: (value: string | undefined) => void;
|
|
24
|
+
disabled?: boolean;
|
|
24
25
|
}
|
|
25
|
-
declare const ProfileTypeSelector: ({ profileTypesData, loading, error, selectedKey, onSelection, flexibleKnownProfilesDetection, }: Props) => JSX.Element;
|
|
26
|
+
declare const ProfileTypeSelector: ({ profileTypesData, loading, error, selectedKey, onSelection, flexibleKnownProfilesDetection, disabled, }: Props) => JSX.Element;
|
|
26
27
|
export default ProfileTypeSelector;
|
|
@@ -110,7 +110,7 @@ export const normalizeProfileTypesData = (types) => {
|
|
|
110
110
|
return a.localeCompare(b);
|
|
111
111
|
});
|
|
112
112
|
};
|
|
113
|
-
const ProfileTypeSelector = ({ profileTypesData, loading = false, error, selectedKey, onSelection, flexibleKnownProfilesDetection = false, }) => {
|
|
113
|
+
const ProfileTypeSelector = ({ profileTypesData, loading = false, error, selectedKey, onSelection, flexibleKnownProfilesDetection = false, disabled, }) => {
|
|
114
114
|
const profileNames = useMemo(() => {
|
|
115
115
|
return (error === undefined || error == null) &&
|
|
116
116
|
profileTypesData !== undefined &&
|
|
@@ -122,6 +122,6 @@ const ProfileTypeSelector = ({ profileTypesData, loading = false, error, selecte
|
|
|
122
122
|
key: name,
|
|
123
123
|
element: profileSelectElement(name, flexibleKnownProfilesDetection),
|
|
124
124
|
}));
|
|
125
|
-
return (_jsx(Select, { items: profileLabels, selectedKey: selectedKey, onSelection: onSelection, placeholder: "Select profile type...", loading: loading, className: "bg-white h-profile-type-dropdown" }));
|
|
125
|
+
return (_jsx(Select, { items: profileLabels, selectedKey: selectedKey, onSelection: onSelection, placeholder: "Select profile type...", loading: loading, className: "bg-white h-profile-type-dropdown", disabled: disabled }));
|
|
126
126
|
};
|
|
127
127
|
export default ProfileTypeSelector;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { QueryServiceClient } from '@parca/client';
|
|
2
|
+
import { DateTimeRange } from '@parca/components';
|
|
3
|
+
import { QuerySelection } from '../ProfileSelector';
|
|
4
|
+
interface Props {
|
|
5
|
+
queryClient: QueryServiceClient;
|
|
6
|
+
selectQuery: (query: QuerySelection) => void;
|
|
7
|
+
enforcedProfileName: string;
|
|
8
|
+
timeRangeSelection: DateTimeRange;
|
|
9
|
+
querySelection: QuerySelection;
|
|
10
|
+
}
|
|
11
|
+
declare const QueryBrowser: ({ queryClient, enforcedProfileName, timeRangeSelection, selectQuery, querySelection, }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export default QueryBrowser;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useEffect, useState } from 'react';
|
|
3
|
+
import { Query } from '@parca/parser';
|
|
4
|
+
import MatchersInput from '../MatchersInput';
|
|
5
|
+
const QueryBrowser = ({ queryClient, enforcedProfileName, timeRangeSelection, selectQuery, querySelection, }) => {
|
|
6
|
+
const [queryExpressionString, setQueryExpressionString] = useState(querySelection.expression);
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
if (enforcedProfileName !== '') {
|
|
9
|
+
const [q, changed] = Query.parse(querySelection.expression).setProfileName(enforcedProfileName);
|
|
10
|
+
if (changed) {
|
|
11
|
+
setQueryExpressionString(q.toString());
|
|
12
|
+
return;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
setQueryExpressionString(querySelection.expression);
|
|
16
|
+
}, [enforcedProfileName, querySelection.expression]);
|
|
17
|
+
const enforcedProfileNameQuery = () => {
|
|
18
|
+
const pq = Query.parse(queryExpressionString);
|
|
19
|
+
const [q] = pq.setProfileName(enforcedProfileName);
|
|
20
|
+
return q;
|
|
21
|
+
};
|
|
22
|
+
const setMatchersString = (matchers) => {
|
|
23
|
+
const newExpressionString = `${''}{${matchers}}`;
|
|
24
|
+
setQueryExpressionString(newExpressionString);
|
|
25
|
+
};
|
|
26
|
+
const setNewQueryExpression = (expr) => {
|
|
27
|
+
const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
|
|
28
|
+
const delta = query.profileType().delta;
|
|
29
|
+
const from = timeRangeSelection.getFromMs();
|
|
30
|
+
const to = timeRangeSelection.getToMs();
|
|
31
|
+
const mergeParams = delta
|
|
32
|
+
? {
|
|
33
|
+
mergeFrom: from,
|
|
34
|
+
mergeTo: to,
|
|
35
|
+
}
|
|
36
|
+
: {};
|
|
37
|
+
selectQuery({
|
|
38
|
+
expression: expr,
|
|
39
|
+
from,
|
|
40
|
+
to,
|
|
41
|
+
timeSelection: timeRangeSelection.getRangeKey(),
|
|
42
|
+
...mergeParams,
|
|
43
|
+
});
|
|
44
|
+
};
|
|
45
|
+
const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
|
|
46
|
+
const setQueryExpression = () => {
|
|
47
|
+
setNewQueryExpression(query.toString());
|
|
48
|
+
};
|
|
49
|
+
return (_jsx(_Fragment, { children: _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query }) }));
|
|
50
|
+
};
|
|
51
|
+
export default QueryBrowser;
|
package/package.json
CHANGED
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.370",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@headlessui/react": "^1.7.19",
|
|
7
7
|
"@iconify/react": "^4.0.0",
|
|
8
8
|
"@parca/client": "^0.16.113",
|
|
9
|
-
"@parca/components": "^0.16.
|
|
9
|
+
"@parca/components": "^0.16.275",
|
|
10
10
|
"@parca/dynamicsize": "^0.16.64",
|
|
11
|
-
"@parca/hooks": "^0.0.
|
|
11
|
+
"@parca/hooks": "^0.0.55",
|
|
12
12
|
"@parca/icons": "^0.16.68",
|
|
13
13
|
"@parca/parser": "^0.16.73",
|
|
14
|
-
"@parca/store": "^0.16.
|
|
15
|
-
"@parca/utilities": "^0.0.
|
|
14
|
+
"@parca/store": "^0.16.144",
|
|
15
|
+
"@parca/utilities": "^0.0.72",
|
|
16
16
|
"@popperjs/core": "^2.11.8",
|
|
17
17
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
18
18
|
"@tanstack/react-query": "^4.0.5",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"access": "public",
|
|
72
72
|
"registry": "https://registry.npmjs.org/"
|
|
73
73
|
},
|
|
74
|
-
"gitHead": "
|
|
74
|
+
"gitHead": "6fb2ee469c00ba81c6b1317771127fdf5806dced"
|
|
75
75
|
}
|
|
@@ -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, {Fragment, useCallback, useMemo, useRef, useState} from 'react';
|
|
14
|
+
import React, {Fragment, useCallback, useId, useMemo, useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import * as d3 from 'd3';
|
|
17
17
|
import {pointer} from 'd3-selection';
|
|
@@ -140,6 +140,7 @@ export const RawMetricsGraph = ({
|
|
|
140
140
|
const [pos, setPos] = useState([0, 0]);
|
|
141
141
|
const [isContextMenuOpen, setIsContextMenuOpen] = useState<boolean>(false);
|
|
142
142
|
const metricPointRef = useRef(null);
|
|
143
|
+
const idForContextMenu = useId();
|
|
143
144
|
|
|
144
145
|
// the time of the selected point is the start of the merge window
|
|
145
146
|
const time: number = parseFloat(profile?.HistoryParams().merge_from);
|
|
@@ -372,7 +373,7 @@ export const RawMetricsGraph = ({
|
|
|
372
373
|
|
|
373
374
|
const selected = findSelectedProfile();
|
|
374
375
|
|
|
375
|
-
const MENU_ID =
|
|
376
|
+
const MENU_ID = `metrics-context-menu-${idForContextMenu}`;
|
|
376
377
|
|
|
377
378
|
const {show} = useContextMenu({
|
|
378
379
|
id: MENU_ID,
|
|
@@ -147,6 +147,7 @@ interface Props {
|
|
|
147
147
|
selectedKey: string | undefined;
|
|
148
148
|
flexibleKnownProfilesDetection?: boolean;
|
|
149
149
|
onSelection: (value: string | undefined) => void;
|
|
150
|
+
disabled?: boolean;
|
|
150
151
|
}
|
|
151
152
|
|
|
152
153
|
const ProfileTypeSelector = ({
|
|
@@ -156,6 +157,7 @@ const ProfileTypeSelector = ({
|
|
|
156
157
|
selectedKey,
|
|
157
158
|
onSelection,
|
|
158
159
|
flexibleKnownProfilesDetection = false,
|
|
160
|
+
disabled,
|
|
159
161
|
}: Props): JSX.Element => {
|
|
160
162
|
const profileNames = useMemo(() => {
|
|
161
163
|
return (error === undefined || error == null) &&
|
|
@@ -178,6 +180,7 @@ const ProfileTypeSelector = ({
|
|
|
178
180
|
placeholder="Select profile type..."
|
|
179
181
|
loading={loading}
|
|
180
182
|
className="bg-white h-profile-type-dropdown"
|
|
183
|
+
disabled={disabled}
|
|
181
184
|
/>
|
|
182
185
|
);
|
|
183
186
|
};
|