@parca/profile 0.19.35 → 0.19.37
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/MatchersInput/index.d.ts.map +1 -1
- package/dist/MatchersInput/index.js +3 -2
- package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/index.js +2 -1
- package/dist/ProfileSelector/QueryControls.d.ts.map +1 -1
- package/dist/ProfileSelector/QueryControls.js +6 -5
- package/dist/ProfileTypeSelector/index.d.ts.map +1 -1
- package/dist/ProfileTypeSelector/index.js +2 -1
- package/dist/ProfileView/components/ProfileFilters/index.d.ts +4 -1
- package/dist/ProfileView/components/ProfileFilters/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/index.js +8 -6
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +2 -1
- package/dist/SimpleMatchers/index.d.ts.map +1 -1
- package/dist/SimpleMatchers/index.js +3 -2
- package/dist/ViewMatchers/index.d.ts.map +1 -1
- package/dist/ViewMatchers/index.js +2 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/package.json +4 -3
- package/src/MatchersInput/index.tsx +6 -1
- package/src/ProfileFlameGraph/index.tsx +6 -1
- package/src/ProfileSelector/QueryControls.tsx +34 -9
- package/src/ProfileTypeSelector/index.tsx +2 -0
- package/src/ProfileView/components/ProfileFilters/index.tsx +55 -32
- package/src/ProfileView/components/Toolbars/index.tsx +2 -0
- package/src/SimpleMatchers/index.tsx +9 -1
- package/src/ViewMatchers/index.tsx +2 -1
- package/src/index.tsx +3 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,14 @@
|
|
|
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.19.37](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.36...@parca/profile@0.19.37) (2025-08-21)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
## [0.19.36](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.35...@parca/profile@0.19.36) (2025-08-15)
|
|
11
|
+
|
|
12
|
+
**Note:** Version bump only for package @parca/profile
|
|
13
|
+
|
|
6
14
|
## [0.19.35](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.34...@parca/profile@0.19.35) (2025-08-12)
|
|
7
15
|
|
|
8
16
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAgB,MAAM,eAAe,CAAC;AAE/F,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAIpC,OAAO,EAAC,iBAAiB,EAAC,MAAM,oBAAoB,CAAC;AAKrD,UAAU,kBAAkB;IAC1B,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,iBAAiB,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,aAAa,GACxB,QAAQ,kBAAkB,EAC1B,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,QAAQ,MAAM,EAAE,KACf,aAyBF,CAAC;AAEF,UAAU,cAAc;IACtB,MAAM,EAAE;QACN,QAAQ,EAAE,MAAM,EAAE,CAAC;QACnB,KAAK,CAAC,EAAE,KAAK,CAAC;KACf,CAAC;IACF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,cAAc,GACzB,QAAQ,kBAAkB,EAC1B,WAAW,MAAM,EACjB,aAAa,MAAM,EACnB,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,cA0BF,CAAC;AAEF,eAAO,MAAM,8BAA8B,GACzC,WAAW,MAAM,EACjB,oBAAoB,iBAAiB,KACpC,MAAM,EASR,CAAC;AAqMF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAWxF"}
|
|
@@ -17,6 +17,7 @@ import cx from 'classnames';
|
|
|
17
17
|
import TextareaAutosize from 'react-textarea-autosize';
|
|
18
18
|
import { useGrpcMetadata } from '@parca/components';
|
|
19
19
|
import { Query } from '@parca/parser';
|
|
20
|
+
import { testId } from '@parca/test-utils';
|
|
20
21
|
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
21
22
|
import { LabelsProvider, useLabels } from '../contexts/MatchersInputLabelsContext';
|
|
22
23
|
import useGrpcQuery from '../useGrpcQuery';
|
|
@@ -193,9 +194,9 @@ const MatchersInput = ({ setMatchersString, runQuery, currentQuery, }) => {
|
|
|
193
194
|
setFocusedInput(false);
|
|
194
195
|
};
|
|
195
196
|
const profileSelected = currentQuery.profileName() === '';
|
|
196
|
-
return (_jsxs("div", { className: "w-full min-w-[300px] flex-1 font-mono relative", children: [_jsx(TextareaAutosize, { ref: inputRef, className: cx('block h-[38px] w-full flex-1 rounded-md border bg-white px-2 py-2 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', profileSelected && 'cursor-not-allowed'), placeholder: profileSelected
|
|
197
|
+
return (_jsxs("div", { className: "w-full min-w-[300px] flex-1 font-mono relative", ...testId('MATCHERS_INPUT_CONTAINER'), children: [_jsx(TextareaAutosize, { ref: inputRef, className: cx('block h-[38px] w-full flex-1 rounded-md border bg-white px-2 py-2 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', profileSelected && 'cursor-not-allowed'), placeholder: profileSelected
|
|
197
198
|
? 'Select a profile first to enter a filter...'
|
|
198
|
-
: 'filter profiles... eg. node="test"', onChange: onChange, value: value, onBlur: unfocus, onFocus: focus, disabled: profileSelected, title: profileSelected
|
|
199
|
+
: 'filter profiles... eg. node="test"', onChange: onChange, value: value, onBlur: unfocus, ...testId('MATCHERS_TEXTAREA'), onFocus: focus, disabled: profileSelected, title: profileSelected
|
|
199
200
|
? 'Select a profile first to enter a filter...'
|
|
200
201
|
: 'filter profiles... eg. node="test"', id: "matchers-input" }), _jsx(SuggestionsList, { isLabelNamesLoading: isLabelNamesLoading, suggestions: suggestionSections, applySuggestion: applySuggestion, inputRef: inputRef.current, runQuery: runQuery, focusedInput: focusedInput, isLabelValuesLoading: isLabelValuesLoading && lastCompleted.type === 'literal', shouldTrimPrefix: shouldHandlePrefixes })] }));
|
|
201
202
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAMpE,OAAO,EAAC,gBAAgB,EAA0B,MAAM,yBAAyB,CAAC;AAIlF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,uBAAuB,GAClC,eAAe,mBAAmB,KACjC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAIpE,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAqC,oPAmBzD,sBAAsB,KAAG,GAAG,CAAC,OAkT/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -16,6 +16,7 @@ import cx from 'classnames';
|
|
|
16
16
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
17
17
|
import { useMeasure } from 'react-use';
|
|
18
18
|
import { FlameGraphSkeleton, SandwichFlameGraphSkeleton, useParcaContext, useURLState, } from '@parca/components';
|
|
19
|
+
import { testId } from '@parca/test-utils';
|
|
19
20
|
import { capitalizeOnlyFirstLetter, divide } from '@parca/utilities';
|
|
20
21
|
import DiffLegend from '../ProfileView/components/DiffLegend';
|
|
21
22
|
import { useProfileViewContext } from '../ProfileView/context/ProfileViewContext';
|
|
@@ -162,6 +163,6 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({ arrow, total, filt
|
|
|
162
163
|
}
|
|
163
164
|
return (_jsx(ErrorContent, { errorMessage: _jsxs(_Fragment, { children: [_jsx("span", { children: capitalizeOnlyFirstLetter(error.message) }), isFlameChart ? flamechartHelpText ?? null : null] }) }));
|
|
164
165
|
}
|
|
165
|
-
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "relative h-full w-full", initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.5 }, children: [compareMode ? _jsx(DiffLegend, {}) : null, _jsx("div", { className: cx(!isInSandwichView ? 'min-h-48' : ''), id: "h-flame-graph", children: _jsx(_Fragment, { children: flameGraph }) }), !isInSandwichView && (_jsxs("p", { className: "my-2 text-xs", children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] }))] }, "flame-graph-loaded") }));
|
|
166
|
+
return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "relative h-full w-full", initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.5 }, children: [compareMode ? _jsx(DiffLegend, {}) : null, _jsx("div", { className: cx(!isInSandwichView ? 'min-h-48' : ''), id: "h-flame-graph", ...testId('FLAMEGRAPH_CONTAINER'), children: _jsx(_Fragment, { children: flameGraph }) }), !isInSandwichView && (_jsxs("p", { className: "my-2 text-xs", children: ["Showing ", totalFormatted, ' ', isFiltered ? (_jsxs("span", { children: ["(", filteredPercentage, "%) filtered of ", totalUnfilteredFormatted, ' '] })) : (_jsx(_Fragment, {})), "values.", ' '] }))] }, "flame-graph-loaded") }));
|
|
166
167
|
};
|
|
167
168
|
export default ProfileFlameGraph;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/QueryControls.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAClD,OAAe,EAAC,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACvE,OAAO,EAAS,aAAa,EAAsB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAC,WAAW,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"QueryControls.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/QueryControls.tsx"],"names":[],"mappings":"AAcA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAClD,OAAe,EAAC,KAAK,cAAc,EAAC,MAAM,cAAc,CAAC;AAEzD,OAAO,EAAC,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACvE,OAAO,EAAS,aAAa,EAAsB,MAAM,mBAAmB,CAAC;AAC7E,OAAO,EAAC,WAAW,EAAE,KAAK,EAAC,MAAM,eAAe,CAAC;AAajD,UAAU,kBAAkB;IAC1B,uBAAuB,EAAE,OAAO,CAAC;IACjC,iBAAiB,EAAE,OAAO,CAAC;IAC3B,0BAA0B,EAAE,OAAO,CAAC;IACpC,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,mBAAmB,EAAE,OAAO,CAAC;IAC7B,mBAAmB,EAAE,MAAM,CAAC;IAC5B,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACnD,iBAAiB,CAAC,EAAE,QAAQ,CAAC;IAC7B,aAAa,CAAC,EAAE;QACd,2BAA2B,CAAC,EAAE,OAAO,CAAC;QACtC,0BAA0B,CAAC,EAAE,OAAO,CAAC;QACrC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;QACtB,mBAAmB,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;KACvC,CAAC;IACF,gBAAgB,EAAE,MAAM,CAAC;IACzB,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,2BAA2B,EAAE,OAAO,CAAC;IACrC,8BAA8B,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,KAAK,EAAE,KAAK,CAAC;IACb,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,kBAAkB,EAAE,aAAa,CAAC;IAClC,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,kBAAkB,CAAC;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,qBAAqB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACjD,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IAC1C,WAAW,EAAE,WAAW,CAAC;CAC1B;AAED,wBAAgB,aAAa,CAAC,EAC5B,uBAAuB,EACvB,gBAAgB,EAChB,mBAAmB,EACnB,mBAAmB,EACnB,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,2BAA2B,EAC3B,8BAA8B,EAC9B,iBAAiB,EACjB,kBAAkB,EAClB,KAAK,EACL,eAAe,EACf,kBAAkB,EAClB,qBAAqB,EACrB,cAAc,EACd,WAAW,EACX,MAAM,EACN,cAAc,EACd,qBAAqB,EACrB,qBAAqB,EACrB,QAAQ,EACR,WAAW,EACX,iBAAiB,EACjB,iBAAiB,GAClB,EAAE,kBAAkB,GAAG,GAAG,CAAC,OAAO,CAiLlC"}
|
|
@@ -14,17 +14,18 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
14
14
|
import { Switch } from '@headlessui/react';
|
|
15
15
|
import Select from 'react-select';
|
|
16
16
|
import { Button, DateTimeRangePicker } from '@parca/components';
|
|
17
|
+
import { testId } from '@parca/test-utils';
|
|
17
18
|
import MatchersInput from '../MatchersInput';
|
|
18
19
|
import ProfileTypeSelector from '../ProfileTypeSelector';
|
|
19
20
|
import SimpleMatchers from '../SimpleMatchers';
|
|
20
21
|
import ViewMatchers from '../ViewMatchers';
|
|
21
22
|
export function QueryControls({ showProfileTypeSelector, profileTypesData, profileTypesLoading, selectedProfileName, setProfileName, viewComponent, setQueryBrowserMode, advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser, setMatchersString, setQueryExpression, query, queryBrowserRef, timeRangeSelection, setTimeRangeSelection, searchDisabled, queryClient, labels, sumBySelection, sumBySelectionLoading, setUserSumBySelection, sumByRef, profileType, showSumBySelector, profileTypesError, }) {
|
|
22
|
-
return (_jsxs("div", { className: "flex w-full flex-wrap items-start gap-2", children: [showProfileTypeSelector && (_jsxs("div", { children: [_jsx("label", { className: "text-xs", children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: profileTypesError, disabled: viewComponent?.disableProfileTypesDropdown })] })), _jsxs("div", { className: "w-full flex-1 flex flex-col gap-1 mt-auto", ref: queryBrowserRef, children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("label", { className: "text-xs", children: "Query" }), viewComponent?.disableExplorativeQuerying !== true && (_jsxs(_Fragment, { children: [_jsxs(Switch, { checked: advancedModeForQueryBrowser, onChange: () => {
|
|
23
|
+
return (_jsxs("div", { className: "flex w-full flex-wrap items-start gap-2", ...testId('QUERY_CONTROLS_CONTAINER'), children: [showProfileTypeSelector && (_jsxs("div", { children: [_jsx("label", { className: "text-xs", ...testId('PROFILE_TYPE_LABEL'), children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: profileTypesError, disabled: viewComponent?.disableProfileTypesDropdown })] })), _jsxs("div", { className: "w-full flex-1 flex flex-col gap-1 mt-auto", ref: queryBrowserRef, ...testId('QUERY_BROWSER_CONTAINER'), children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("div", { className: "flex items-center gap-3", children: [_jsx("label", { className: "text-xs", ...testId('QUERY_LABEL'), children: "Query" }), viewComponent?.disableExplorativeQuerying !== true && (_jsxs(_Fragment, { children: [_jsxs(Switch, { checked: advancedModeForQueryBrowser, onChange: () => {
|
|
23
24
|
setAdvancedModeForQueryBrowser(!advancedModeForQueryBrowser);
|
|
24
25
|
setQueryBrowserMode(advancedModeForQueryBrowser ? 'simple' : 'advanced');
|
|
25
|
-
}, className: `${advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'} relative inline-flex h-[20px] w-[44px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75`, children: [_jsx("span", { className: "sr-only", children: "Use setting" }), _jsx("span", { "aria-hidden": "true", className: `${advancedModeForQueryBrowser ? 'translate-x-6' : 'translate-x-0'} pointer-events-none inline-block h-[16px] w-[16px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out` })] }), _jsx("label", { className: "text-xs", children: "Advanced Mode" })] }))] }), viewComponent?.createViewComponent] }), viewComponent?.disableExplorativeQuerying === true &&
|
|
26
|
+
}, className: `${advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'} relative inline-flex h-[20px] w-[44px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75`, ...testId('ADVANCED_MODE_SWITCH'), children: [_jsx("span", { className: "sr-only", children: "Use setting" }), _jsx("span", { "aria-hidden": "true", className: `${advancedModeForQueryBrowser ? 'translate-x-6' : 'translate-x-0'} pointer-events-none inline-block h-[16px] w-[16px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out` })] }), _jsx("label", { className: "text-xs", ...testId('QUERY_MODE_LABEL'), children: "Advanced Mode" })] }))] }), viewComponent?.createViewComponent] }), viewComponent?.disableExplorativeQuerying === true &&
|
|
26
27
|
viewComponent?.labelnames !== undefined &&
|
|
27
|
-
viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : advancedModeForQueryBrowser ? (_jsx(MatchersInput, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : (_jsx(SimpleMatchers, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() }, query.toString()))] }), showSumBySelector && (_jsxs("div", { children: [_jsx("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: _jsx("label", { className: "text-xs", children: "Sum by" }) }), _jsx(Select, { id: "h-sum-by-selector", defaultValue: [], isMulti: true, isClearable: false, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-full max-w-80", classNamePrefix: "parca-select", value: (sumBySelection ?? []).map(sumBy => ({ label: sumBy, value: sumBy })), onChange: newValue => {
|
|
28
|
+
viewComponent?.labelnames.length >= 1 ? (_jsx(ViewMatchers, { labelNames: viewComponent.labelnames, setMatchersString: setMatchersString, profileType: selectedProfileName, runQuery: setQueryExpression, currentQuery: query, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : advancedModeForQueryBrowser ? (_jsx(MatchersInput, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() })) : (_jsx(SimpleMatchers, { setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName, queryBrowserRef: queryBrowserRef, queryClient: queryClient, start: timeRangeSelection.getFromMs(), end: timeRangeSelection.getToMs() }, query.toString()))] }), showSumBySelector && (_jsxs("div", { ...testId('SUM_BY_CONTAINER'), children: [_jsx("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: _jsx("label", { className: "text-xs", ...testId('SUM_BY_LABEL'), children: "Sum by" }) }), _jsx(Select, { id: "h-sum-by-selector", "data-testid": testId('SUM_BY_SELECT')['data-testid'], defaultValue: [], isMulti: true, isClearable: false, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-full max-w-80", classNamePrefix: "parca-select", value: (sumBySelection ?? []).map(sumBy => ({ label: sumBy, value: sumBy })), onChange: newValue => {
|
|
28
29
|
setUserSumBySelection(newValue.map(option => option.value));
|
|
29
30
|
}, placeholder: "Labels...", styles: {
|
|
30
31
|
indicatorSeparator: () => ({ display: 'none' }),
|
|
@@ -47,8 +48,8 @@ export function QueryControls({ showProfileTypeSelector, profileTypesData, profi
|
|
|
47
48
|
setQueryExpression(true);
|
|
48
49
|
currentRef.blur();
|
|
49
50
|
}
|
|
50
|
-
} })] })), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsxs("div", { children: [_jsx("label", { className: "text-xs", children: "\u00A0" }), _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
|
|
51
|
+
} })] })), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection, ...testId('DATE_TIME_RANGE_PICKER') }), _jsxs("div", { children: [_jsx("label", { className: "text-xs", ...testId('SEARCH_BUTTON_LABEL'), children: "\u00A0" }), _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
|
|
51
52
|
e.preventDefault();
|
|
52
53
|
setQueryExpression(true);
|
|
53
|
-
}, id: "h-matcher-search-button", children: "Search" })] })] }));
|
|
54
|
+
}, id: "h-matcher-search-button", ...testId('SEARCH_BUTTON'), children: "Search" })] })] }));
|
|
54
55
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileTypeSelector/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAChE,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileTypeSelector/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAC,WAAW,EAAE,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAChE,OAAO,EAAS,KAAK,aAAa,EAAC,MAAM,mBAAmB,CAAC;AAG7D,UAAU,gBAAgB;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,UAAU,iBAAiB;IACzB,CAAC,GAAG,EAAE,MAAM,GAAG,gBAAgB,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,EAAE,iBAiF/B,CAAC;AAEF,wBAAgB,gCAAgC,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,GAAG,SAAS,CAU3F;AAED,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,MAAM,EACZ,8BAA8B,EAAE,OAAO,GACtC,aAAa,CAiBf;AAED,eAAO,MAAM,oBAAoB,GAAI,MAAM,WAAW,KAAG,MAIxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,GAAI,OAAO,WAAW,EAAE,KAAG,MAAM,EAItE,CAAC;AAEF,UAAU,KAAK;IACb,gBAAgB,CAAC,EAAE,oBAAoB,CAAC;IACxC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,QAAQ,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,8BAA8B,CAAC,EAAE,OAAO,CAAC;IACzC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IACjD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,mBAAmB,GAAI,2GAQ1B,KAAK,KAAG,GAAG,CAAC,OA0Bd,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
|
|
@@ -13,6 +13,7 @@ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-run
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { useMemo } from 'react';
|
|
15
15
|
import { Select } from '@parca/components';
|
|
16
|
+
import { testId } from '@parca/test-utils';
|
|
16
17
|
export const wellKnownProfiles = {
|
|
17
18
|
'block:contentions:count:contentions:count': {
|
|
18
19
|
name: 'Block Contentions Total',
|
|
@@ -138,6 +139,6 @@ const ProfileTypeSelector = ({ profileTypesData, loading = false, error, selecte
|
|
|
138
139
|
key: name,
|
|
139
140
|
element: profileSelectElement(name, flexibleKnownProfilesDetection),
|
|
140
141
|
}));
|
|
141
|
-
return (_jsx(Select, { items: profileLabels, selectedKey: selectedKey, onSelection: onSelection, placeholder: "Select profile type...", loading: loading, className: "bg-white h-profile-type-dropdown", disabled: disabled }));
|
|
142
|
+
return (_jsx(Select, { items: profileLabels, selectedKey: selectedKey, onSelection: onSelection, placeholder: "Select profile type...", loading: loading, className: "bg-white h-profile-type-dropdown", disabled: disabled, ...testId('PROFILE_TYPE_SELECTOR') }));
|
|
142
143
|
};
|
|
143
144
|
export default ProfileTypeSelector;
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { type ProfileFilter } from './useProfileFilters';
|
|
2
2
|
export declare const isFilterComplete: (filter: ProfileFilter) => boolean;
|
|
3
|
-
|
|
3
|
+
export interface ProfileFiltersProps {
|
|
4
|
+
readOnly?: boolean;
|
|
5
|
+
}
|
|
6
|
+
declare const ProfileFilters: ({ readOnly }?: ProfileFiltersProps) => JSX.Element;
|
|
4
7
|
export default ProfileFilters;
|
|
5
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/index.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAoB,KAAK,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAE1E,eAAO,MAAM,gBAAgB,GAAI,QAAQ,aAAa,KAAG,OASxD,CAAC;AAyIF,QAAA,MAAM,cAAc,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ProfileFilters/index.tsx"],"names":[],"mappings":"AAsBA,OAAO,EAAoB,KAAK,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAE1E,eAAO,MAAM,gBAAgB,GAAI,QAAQ,aAAa,KAAG,OASxD,CAAC;AAyIF,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,QAAA,MAAM,cAAc,GAAI,eAAoB,mBAAwB,KAAG,GAAG,CAAC,OAsM1E,CAAC;AAEF,eAAe,cAAc,CAAC"}
|
|
@@ -139,7 +139,7 @@ const numberMatchTypeItems = [
|
|
|
139
139
|
},
|
|
140
140
|
},
|
|
141
141
|
];
|
|
142
|
-
const ProfileFilters = () => {
|
|
142
|
+
const ProfileFilters = ({ readOnly = false } = {}) => {
|
|
143
143
|
const { profileSource } = useProfileViewContext();
|
|
144
144
|
const currentProfileType = profileSource?.ProfileType()?.toString();
|
|
145
145
|
const filterTypeItems = getFilterTypeItems(currentProfileType);
|
|
@@ -158,7 +158,7 @@ const ProfileFilters = () => {
|
|
|
158
158
|
const isNumberField = filter.field === 'address' || filter.field === 'line_number';
|
|
159
159
|
const matchTypeItems = isNumberField ? numberMatchTypeItems : stringMatchTypeItems;
|
|
160
160
|
const isPresetFilter = filter.type != null && isPresetKey(filter.type);
|
|
161
|
-
return (_jsxs("div", { className: "flex items-center gap-0", children: [_jsx(Select, { items: filterTypeItems, selectedKey: filter.type, placeholder: "Select Filter", onSelection: key => {
|
|
161
|
+
return (_jsxs("div", { className: "flex items-center gap-0", children: [_jsx(Select, { items: filterTypeItems, selectedKey: filter.type, placeholder: "Select Filter", disabled: readOnly, onSelection: key => {
|
|
162
162
|
// Check if this is a preset selection
|
|
163
163
|
if (isPresetKey(key)) {
|
|
164
164
|
const preset = getPresetByKey(key);
|
|
@@ -190,7 +190,7 @@ const ProfileFilters = () => {
|
|
|
190
190
|
});
|
|
191
191
|
}
|
|
192
192
|
}
|
|
193
|
-
}, className: cx('
|
|
193
|
+
}, className: cx('gap-0 focus:z-50 focus:relative focus:outline-1', readOnly ? '' : 'pr-1', readOnly && isPresetFilter ? 'rounded-md' : 'rounded-l-md rounded-r-none', !readOnly && (isPresetFilter ? 'rounded-r-none border-r-0' : 'rounded-r-none'), readOnly ? 'w-auto' : filter.type != null ? 'border-r-0 w-auto' : 'w-32'), hideCaretDropdown: readOnly }), filter.type != null && !isPresetFilter && (_jsxs(_Fragment, { children: [_jsx(Select, { items: fieldItems, selectedKey: filter.field ?? '', disabled: readOnly, onSelection: key => {
|
|
194
194
|
const newField = key;
|
|
195
195
|
const isNewFieldNumber = newField === 'address' || newField === 'line_number';
|
|
196
196
|
const isCurrentFieldNumber = filter.field === 'address' || filter.field === 'line_number';
|
|
@@ -203,7 +203,7 @@ const ProfileFilters = () => {
|
|
|
203
203
|
else {
|
|
204
204
|
updateFilter(filter.id, { field: newField });
|
|
205
205
|
}
|
|
206
|
-
}, className:
|
|
206
|
+
}, className: cx('rounded-none border-r-0 w-32 gap-0 focus:z-50 focus:relative focus:outline-1', readOnly ? '' : 'pr-1'), hideCaretDropdown: readOnly }), _jsx(Select, { items: matchTypeItems, selectedKey: filter.matchType ?? '', disabled: readOnly, onSelection: key => updateFilter(filter.id, { matchType: key }), className: cx('rounded-none border-r-0 gap-0 focus:z-50 focus:relative focus:outline-1', readOnly ? '' : 'pr-1'), hideCaretDropdown: readOnly }), _jsx(Input, { placeholder: "Value", value: filter.value, disabled: readOnly, onChange: e => updateFilter(filter.id, { value: e.target.value }), onKeyDown: handleKeyDown, className: "rounded-none w-36 text-sm focus:outline-1" })] })), !readOnly && (_jsx(Button, { variant: "neutral", onClick: () => {
|
|
207
207
|
// If we're displaying local filters and this is the last one, reset everything
|
|
208
208
|
if (localFilters.length > 0 && localFilters.length === 1) {
|
|
209
209
|
resetFilters();
|
|
@@ -216,7 +216,9 @@ const ProfileFilters = () => {
|
|
|
216
216
|
else {
|
|
217
217
|
removeFilter(filter.id);
|
|
218
218
|
}
|
|
219
|
-
}, className: cx('h-[38px] p-3', filter.type != null
|
|
220
|
-
|
|
219
|
+
}, className: cx('h-[38px] p-3', filter.type != null
|
|
220
|
+
? 'rounded-none rounded-r-md'
|
|
221
|
+
: 'rounded-l-none rounded-r-md'), children: _jsx(Icon, { icon: "mdi:close", className: "h-4 w-4" }) }))] }, filter.id));
|
|
222
|
+
}), !readOnly && 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" }) })), !readOnly && 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" })] }))] }), !readOnly && localFilters.length > 0 && (_jsx(Button, { variant: "primary", onClick: onApplyFilters, disabled: !hasUnsavedChanges || !localFilters.some(isFilterComplete), className: cx('flex items-center gap-2 sticky top-0'), children: _jsx("span", { children: "Apply" }) }))] }));
|
|
221
223
|
};
|
|
222
224
|
export default ProfileFilters;
|
|
@@ -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;
|
|
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;AAG1C,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,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAyF9D,CAAC"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Icon } from '@iconify/react';
|
|
3
3
|
import { Button } from '@parca/components';
|
|
4
|
+
import { testId } from '@parca/test-utils';
|
|
4
5
|
import { useDashboard } from '../../context/DashboardContext';
|
|
5
6
|
import GroupByDropdown from '../ActionButtons/GroupByDropdown';
|
|
6
7
|
import InvertCallStack from '../InvertCallStack';
|
|
@@ -13,7 +14,7 @@ export const TableToolbar = ({ profileType, total, filtered }) => {
|
|
|
13
14
|
return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end", children: _jsx(TableColumnsDropdown, { profileType: profileType, total: total, filtered: filtered }) }) }));
|
|
14
15
|
};
|
|
15
16
|
export const FlameGraphToolbar = ({ curPath, setNewCurPath }) => {
|
|
16
|
-
return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end", children: _jsxs(Button, { variant: "neutral", className: "gap-2 w-max h-fit", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, id: "h-reset-graph", children: ["Reset graph", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }) }) }));
|
|
17
|
+
return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end", children: _jsxs(Button, { variant: "neutral", className: "gap-2 w-max h-fit", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, id: "h-reset-graph", ...testId('FLAMEGRAPH_RESET_BUTTON'), children: ["Reset graph", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }) }) }));
|
|
17
18
|
};
|
|
18
19
|
export const SandwichFlameGraphToolbar = ({ resetSandwichFunctionName, sandwichFunctionName, }) => {
|
|
19
20
|
return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName === undefined || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SimpleMatchers/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,OAAe,EAAC,KAAK,UAAU,EAAC,MAAM,UAAU,CAAC;AAEjD,UAAU,KAAK;IACb,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,KAAK,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;IACjD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAoBD,eAAO,MAAM,wBAAwB,GAAI,YAAY,MAAM,EAAE,KAAG,UAAU,EAQzE,CAAC;AA2WF,MAAM,CAAC,OAAO,UAAU,yBAAyB,CAAC,KAAK,EAAE,KAAK,GAAG,GAAG,CAAC,OAAO,CAoB3E"}
|
|
@@ -16,6 +16,7 @@ import { Icon } from '@iconify/react';
|
|
|
16
16
|
import { useQueryClient } from '@tanstack/react-query';
|
|
17
17
|
import cx from 'classnames';
|
|
18
18
|
import { useGrpcMetadata } from '@parca/components';
|
|
19
|
+
import { testId } from '@parca/test-utils';
|
|
19
20
|
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
20
21
|
import { LabelProvider, useLabels } from '../contexts/SimpleMatchersLabelContext';
|
|
21
22
|
import { useUtilizationLabels } from '../contexts/UtilizationLabelsContext';
|
|
@@ -241,9 +242,9 @@ const SimpleMatchers = ({ queryClient, setMatchersString, currentQuery, profileT
|
|
|
241
242
|
};
|
|
242
243
|
}, [queryRows, fetchLabelValuesUnified]);
|
|
243
244
|
const isRowRegex = (row) => row.operator === '=~' || row.operator === '!~';
|
|
244
|
-
return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", children: [_jsx(Select, { items: labelNameOptions, onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none" }), _jsx(Select, { items: transformLabelsForSelect(row.labelValues), onSelection: value => handleUpdateRow(index, 'labelValue', value), placeholder: "Select label value", selectedKey: row.labelValue, className: "rounded-none ring-0 focus:ring-0 outline-none max-w-48", optionsClassname: cx('max-w-[300px]', {
|
|
245
|
+
return (_jsxs("div", { className: `flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`, id: "simple-matchers", ...testId('SIMPLE_MATCHERS_CONTAINER'), children: [visibleRows.map((row, index) => (_jsxs("div", { className: "flex items-center", ...testId('SIMPLE_MATCHER_ROW'), children: [_jsx(Select, { items: labelNameOptions, onSelection: value => handleUpdateRow(index, 'labelName', value), placeholder: "Select label name", selectedKey: row.labelName, className: "rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none", loading: labelNamesLoading, searchable: true, ...testId('LABEL_NAME_SELECT') }), _jsx(Select, { items: operatorOptions, onSelection: value => handleUpdateRow(index, 'operator', value), selectedKey: row.operator, className: "rounded-none ring-0 focus:ring-0 outline-none", ...testId('OPERATOR_SELECT') }), _jsx(Select, { items: transformLabelsForSelect(row.labelValues), onSelection: value => handleUpdateRow(index, 'labelValue', value), placeholder: "Select label value", selectedKey: row.labelValue, className: "rounded-none ring-0 focus:ring-0 outline-none max-w-48", optionsClassname: cx('max-w-[300px]', {
|
|
245
246
|
'w-[300px]': isRowRegex(row),
|
|
246
|
-
}), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row) }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && (_jsx("button", { onClick: () => setShowAll(!showAll), className: "mr-2 px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900", children: showAll ? 'Show less' : `Show ${hiddenRowsCount} more` })), _jsx("button", { onClick: addNewRow, className: "p-2 border-gray-200 dark:bg-gray-900 dark:border-gray-600 border rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", children: _jsx(Icon, { icon: "material-symbols:add", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }));
|
|
247
|
+
}), searchable: true, disabled: row.labelName === '', loading: row.isLoading, onButtonClick: () => handleLabelValueClick(index), editable: isRowRegex(row), ...testId('LABEL_VALUE_SELECT') }), _jsx("button", { onClick: () => removeRow(index), className: cx('p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'), ...testId('REMOVE_MATCHER_BUTTON'), children: _jsx(Icon, { icon: "carbon:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }, index))), queryRows.length > 3 && (_jsx("button", { onClick: () => setShowAll(!showAll), className: "mr-2 px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900", ...testId(showAll ? 'SHOW_LESS_BUTTON' : 'SHOW_MORE_BUTTON'), children: showAll ? 'Show less' : `Show ${hiddenRowsCount} more` })), _jsx("button", { onClick: addNewRow, className: "p-2 border-gray-200 dark:bg-gray-900 dark:border-gray-600 border rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", ...testId('ADD_MATCHER_BUTTON'), children: _jsx(Icon, { icon: "material-symbols:add", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) })] }));
|
|
247
248
|
};
|
|
248
249
|
export default function SimpleMathersWithProvider(props) {
|
|
249
250
|
const labelNameFromMatchers = useMemo(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ViewMatchers/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAKtE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ViewMatchers/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiD,MAAM,OAAO,CAAC;AAKtE,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,UAAU,KAAK;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,YAAY,EAAE,KAAK,CAAC;IACpB,WAAW,EAAE,kBAAkB,CAAC;IAChC,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACzC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,QAAA,MAAM,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,KAAK,CAqKjC,CAAC;AAEF,eAAe,YAAY,CAAC"}
|
|
@@ -15,6 +15,7 @@ import { useCallback, useEffect, useRef, useState } from 'react';
|
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
16
|
import cx from 'classnames';
|
|
17
17
|
import { useGrpcMetadata } from '@parca/components';
|
|
18
|
+
import { testId } from '@parca/test-utils';
|
|
18
19
|
import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
|
|
19
20
|
import CustomSelect from '../SimpleMatchers/Select';
|
|
20
21
|
const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatchersString, start, end, currentQuery, }) => {
|
|
@@ -108,6 +109,6 @@ const ViewMatchers = ({ labelNames, profileType, queryClient, runQuery, setMatch
|
|
|
108
109
|
element: { active: _jsx(_Fragment, { children: value }), expanded: _jsx(_Fragment, { children: value }) },
|
|
109
110
|
}));
|
|
110
111
|
}, []);
|
|
111
|
-
return (_jsx("div", { className: "flex flex-wrap gap-2", children: labelNames.map(labelName => (_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "relative border shadow-sm px-4 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-sm flex gap-2 items-center justify-between bg-gray-100 dark:bg-gray-700 rounded-l-md border-gray-300 dark:border-gray-600", children: labelName }), _jsx(CustomSelect, { searchable: true, placeholder: "Select value", items: transformValuesForSelect(labelValuesMap[labelName] ?? []), onSelection: (value) => handleSelection(labelName, value), selectedKey: selectionsRef.current[labelName] ?? undefined, className: cx('rounded-l-none border-l-0', selectionsRef.current[labelName] != null && 'border-r-0 rounded-r-none'), loading: isLoading[labelName] ?? false }), selectionsRef.current[labelName] != null && (_jsx("button", { onClick: () => handleReset(labelName), className: "p-2 border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-600 border rounded-r-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", "aria-label": `Reset ${labelName} selection`, children: _jsx(Icon, { icon: "mdi:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) }))] }, labelName))) }));
|
|
112
|
+
return (_jsx("div", { className: "flex flex-wrap gap-2", ...testId('VIEW_MATCHERS_CONTAINER'), children: labelNames.map(labelName => (_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: "relative border shadow-sm px-4 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-sm flex gap-2 items-center justify-between bg-gray-100 dark:bg-gray-700 rounded-l-md border-gray-300 dark:border-gray-600", children: labelName }), _jsx(CustomSelect, { searchable: true, placeholder: "Select value", items: transformValuesForSelect(labelValuesMap[labelName] ?? []), onSelection: (value) => handleSelection(labelName, value), selectedKey: selectionsRef.current[labelName] ?? undefined, className: cx('rounded-l-none border-l-0', selectionsRef.current[labelName] != null && 'border-r-0 rounded-r-none'), loading: isLoading[labelName] ?? false }), selectionsRef.current[labelName] != null && (_jsx("button", { onClick: () => handleReset(labelName), className: "p-2 border-gray-200 bg-white dark:bg-gray-900 dark:border-gray-600 border rounded-r-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500", "aria-label": `Reset ${labelName} selection`, children: _jsx(Icon, { icon: "mdi:close", className: "h-5 w-5 text-gray-400", "aria-hidden": "true" }) }))] }, labelName))) }));
|
|
112
113
|
};
|
|
113
114
|
export default ViewMatchers;
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,8 @@ export * from './utils';
|
|
|
11
11
|
export * from './ProfileTypeSelector';
|
|
12
12
|
export * from './SourceView';
|
|
13
13
|
export * from './ProfileMetricsGraph';
|
|
14
|
+
export { default as ProfileFilters } from './ProfileView/components/ProfileFilters';
|
|
15
|
+
export { useProfileFiltersUrlState } from './ProfileView/components/ProfileFilters/useProfileFiltersUrlState';
|
|
14
16
|
export declare const DEFAULT_PROFILE_EXPLORER_PARAM_VALUES: {
|
|
15
17
|
dashboard_items: string;
|
|
16
18
|
};
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,eAAe,EAAE,EAAC,sBAAsB,EAAC,MAAM,mBAAmB,CAAC;AAC1E,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,YAAY,MAAM,yBAAyB,CAAC;AAEnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAC,qBAAqB,EAAC,MAAM,2DAA2D,CAAC;AAChG,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AAEtC,eAAO,MAAM,qCAAqC;;CAEjD,CAAC;AAEF,OAAO,EAAC,eAAe,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAC9C,OAAO,eAAe,EAAE,EAAC,sBAAsB,EAAC,MAAM,mBAAmB,CAAC;AAC1E,OAAO,mBAAmB,MAAM,uBAAuB,CAAC;AACxD,OAAO,YAAY,MAAM,yBAAyB,CAAC;AAEnD,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAC,qBAAqB,EAAC,MAAM,2DAA2D,CAAC;AAChG,cAAc,eAAe,CAAC;AAC9B,cAAc,uBAAuB,CAAC;AACtC,cAAc,SAAS,CAAC;AACxB,cAAc,uBAAuB,CAAC;AACtC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AAEtC,OAAO,EAAC,OAAO,IAAI,cAAc,EAAC,MAAM,yCAAyC,CAAC;AAClF,OAAO,EAAC,yBAAyB,EAAC,MAAM,mEAAmE,CAAC;AAE5G,eAAO,MAAM,qCAAqC;;CAEjD,CAAC;AAEF,OAAO,EAAC,eAAe,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,YAAY,EAAE,aAAa,EAAC,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -23,6 +23,8 @@ export * from './utils';
|
|
|
23
23
|
export * from './ProfileTypeSelector';
|
|
24
24
|
export * from './SourceView';
|
|
25
25
|
export * from './ProfileMetricsGraph';
|
|
26
|
+
export { default as ProfileFilters } from './ProfileView/components/ProfileFilters';
|
|
27
|
+
export { useProfileFiltersUrlState } from './ProfileView/components/ProfileFilters/useProfileFiltersUrlState';
|
|
26
28
|
export const DEFAULT_PROFILE_EXPLORER_PARAM_VALUES = {
|
|
27
29
|
dashboard_items: 'flamegraph',
|
|
28
30
|
};
|
package/package.json
CHANGED
|
@@ -1,18 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.37",
|
|
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
9
|
"@parca/client": "0.17.3",
|
|
10
|
-
"@parca/components": "0.16.
|
|
10
|
+
"@parca/components": "0.16.358",
|
|
11
11
|
"@parca/dynamicsize": "0.16.65",
|
|
12
12
|
"@parca/hooks": "0.0.99",
|
|
13
13
|
"@parca/icons": "0.16.72",
|
|
14
14
|
"@parca/parser": "0.16.79",
|
|
15
15
|
"@parca/store": "0.16.183",
|
|
16
|
+
"@parca/test-utils": "0.0.2",
|
|
16
17
|
"@parca/utilities": "0.0.106",
|
|
17
18
|
"@popperjs/core": "^2.11.8",
|
|
18
19
|
"@protobuf-ts/runtime-rpc": "^2.5.0",
|
|
@@ -78,5 +79,5 @@
|
|
|
78
79
|
"access": "public",
|
|
79
80
|
"registry": "https://registry.npmjs.org/"
|
|
80
81
|
},
|
|
81
|
-
"gitHead": "
|
|
82
|
+
"gitHead": "7a6143408ac1e4108e8bfe4725f67f4650b613d4"
|
|
82
83
|
}
|
|
@@ -20,6 +20,7 @@ import TextareaAutosize from 'react-textarea-autosize';
|
|
|
20
20
|
import {LabelsRequest, LabelsResponse, QueryServiceClient, ValuesRequest} from '@parca/client';
|
|
21
21
|
import {useGrpcMetadata} from '@parca/components';
|
|
22
22
|
import {Query} from '@parca/parser';
|
|
23
|
+
import {testId} from '@parca/test-utils';
|
|
23
24
|
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
24
25
|
|
|
25
26
|
import {UtilizationLabels} from '../ProfileSelector';
|
|
@@ -289,7 +290,10 @@ const MatchersInput = ({
|
|
|
289
290
|
const profileSelected = currentQuery.profileName() === '';
|
|
290
291
|
|
|
291
292
|
return (
|
|
292
|
-
<div
|
|
293
|
+
<div
|
|
294
|
+
className="w-full min-w-[300px] flex-1 font-mono relative"
|
|
295
|
+
{...testId('MATCHERS_INPUT_CONTAINER')}
|
|
296
|
+
>
|
|
293
297
|
<TextareaAutosize
|
|
294
298
|
ref={inputRef}
|
|
295
299
|
className={cx(
|
|
@@ -304,6 +308,7 @@ const MatchersInput = ({
|
|
|
304
308
|
onChange={onChange}
|
|
305
309
|
value={value}
|
|
306
310
|
onBlur={unfocus}
|
|
311
|
+
{...testId('MATCHERS_TEXTAREA')}
|
|
307
312
|
onFocus={focus}
|
|
308
313
|
disabled={profileSelected} // Disable input if no profile has been selected
|
|
309
314
|
title={
|
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
useURLState,
|
|
26
26
|
} from '@parca/components';
|
|
27
27
|
import {ProfileType} from '@parca/parser';
|
|
28
|
+
import {testId} from '@parca/test-utils';
|
|
28
29
|
import {capitalizeOnlyFirstLetter, divide} from '@parca/utilities';
|
|
29
30
|
|
|
30
31
|
import {MergedProfileSource, ProfileSource} from '../ProfileSource';
|
|
@@ -380,7 +381,11 @@ const ProfileFlameGraph = function ProfileFlameGraphNonMemo({
|
|
|
380
381
|
transition={{duration: 0.5}}
|
|
381
382
|
>
|
|
382
383
|
{compareMode ? <DiffLegend /> : null}
|
|
383
|
-
<div
|
|
384
|
+
<div
|
|
385
|
+
className={cx(!isInSandwichView ? 'min-h-48' : '')}
|
|
386
|
+
id="h-flame-graph"
|
|
387
|
+
{...testId('FLAMEGRAPH_CONTAINER')}
|
|
388
|
+
>
|
|
384
389
|
<>{flameGraph}</>
|
|
385
390
|
</div>
|
|
386
391
|
{!isInSandwichView && (
|
|
@@ -18,6 +18,7 @@ import Select, {type SelectInstance} from 'react-select';
|
|
|
18
18
|
import {ProfileTypesResponse, QueryServiceClient} from '@parca/client';
|
|
19
19
|
import {Button, DateTimeRange, DateTimeRangePicker} from '@parca/components';
|
|
20
20
|
import {ProfileType, Query} from '@parca/parser';
|
|
21
|
+
import {testId} from '@parca/test-utils';
|
|
21
22
|
|
|
22
23
|
import MatchersInput from '../MatchersInput';
|
|
23
24
|
import ProfileTypeSelector from '../ProfileTypeSelector';
|
|
@@ -92,10 +93,15 @@ export function QueryControls({
|
|
|
92
93
|
profileTypesError,
|
|
93
94
|
}: QueryControlsProps): JSX.Element {
|
|
94
95
|
return (
|
|
95
|
-
<div
|
|
96
|
+
<div
|
|
97
|
+
className="flex w-full flex-wrap items-start gap-2"
|
|
98
|
+
{...testId('QUERY_CONTROLS_CONTAINER')}
|
|
99
|
+
>
|
|
96
100
|
{showProfileTypeSelector && (
|
|
97
101
|
<div>
|
|
98
|
-
<label className="text-xs"
|
|
102
|
+
<label className="text-xs" {...testId('PROFILE_TYPE_LABEL')}>
|
|
103
|
+
Profile type
|
|
104
|
+
</label>
|
|
99
105
|
<ProfileTypeSelector
|
|
100
106
|
profileTypesData={profileTypesData}
|
|
101
107
|
loading={profileTypesLoading}
|
|
@@ -107,10 +113,16 @@ export function QueryControls({
|
|
|
107
113
|
</div>
|
|
108
114
|
)}
|
|
109
115
|
|
|
110
|
-
<div
|
|
116
|
+
<div
|
|
117
|
+
className="w-full flex-1 flex flex-col gap-1 mt-auto"
|
|
118
|
+
ref={queryBrowserRef}
|
|
119
|
+
{...testId('QUERY_BROWSER_CONTAINER')}
|
|
120
|
+
>
|
|
111
121
|
<div className="flex items-center justify-between">
|
|
112
122
|
<div className="flex items-center gap-3">
|
|
113
|
-
<label className="text-xs">
|
|
123
|
+
<label className="text-xs" {...testId('QUERY_LABEL')}>
|
|
124
|
+
Query
|
|
125
|
+
</label>
|
|
114
126
|
{viewComponent?.disableExplorativeQuerying !== true && (
|
|
115
127
|
<>
|
|
116
128
|
<Switch
|
|
@@ -122,6 +134,7 @@ export function QueryControls({
|
|
|
122
134
|
className={`${
|
|
123
135
|
advancedModeForQueryBrowser ? 'bg-indigo-600' : 'bg-gray-400 dark:bg-gray-800'
|
|
124
136
|
} relative inline-flex h-[20px] w-[44px] shrink-0 cursor-pointer rounded-full border-2 border-transparent transition-colors duration-200 ease-in-out focus:outline-none focus-visible:ring-2 focus-visible:ring-white/75`}
|
|
137
|
+
{...testId('ADVANCED_MODE_SWITCH')}
|
|
125
138
|
>
|
|
126
139
|
<span className="sr-only">Use setting</span>
|
|
127
140
|
<span
|
|
@@ -131,7 +144,9 @@ export function QueryControls({
|
|
|
131
144
|
} pointer-events-none inline-block h-[16px] w-[16px] transform rounded-full bg-white shadow-lg ring-0 transition duration-200 ease-in-out`}
|
|
132
145
|
/>
|
|
133
146
|
</Switch>
|
|
134
|
-
<label className="text-xs"
|
|
147
|
+
<label className="text-xs" {...testId('QUERY_MODE_LABEL')}>
|
|
148
|
+
Advanced Mode
|
|
149
|
+
</label>
|
|
135
150
|
</>
|
|
136
151
|
)}
|
|
137
152
|
</div>
|
|
@@ -177,12 +192,15 @@ export function QueryControls({
|
|
|
177
192
|
</div>
|
|
178
193
|
|
|
179
194
|
{showSumBySelector && (
|
|
180
|
-
<div>
|
|
195
|
+
<div {...testId('SUM_BY_CONTAINER')}>
|
|
181
196
|
<div className="mb-0.5 mt-1.5 flex items-center justify-between">
|
|
182
|
-
<label className="text-xs"
|
|
197
|
+
<label className="text-xs" {...testId('SUM_BY_LABEL')}>
|
|
198
|
+
Sum by
|
|
199
|
+
</label>
|
|
183
200
|
</div>
|
|
184
201
|
<Select<SelectOption, true>
|
|
185
202
|
id="h-sum-by-selector"
|
|
203
|
+
data-testid={testId('SUM_BY_SELECT')['data-testid']}
|
|
186
204
|
defaultValue={[]}
|
|
187
205
|
isMulti
|
|
188
206
|
isClearable={false}
|
|
@@ -226,10 +244,16 @@ export function QueryControls({
|
|
|
226
244
|
</div>
|
|
227
245
|
)}
|
|
228
246
|
|
|
229
|
-
<DateTimeRangePicker
|
|
247
|
+
<DateTimeRangePicker
|
|
248
|
+
onRangeSelection={setTimeRangeSelection}
|
|
249
|
+
range={timeRangeSelection}
|
|
250
|
+
{...testId('DATE_TIME_RANGE_PICKER')}
|
|
251
|
+
/>
|
|
230
252
|
|
|
231
253
|
<div>
|
|
232
|
-
<label className="text-xs"
|
|
254
|
+
<label className="text-xs" {...testId('SEARCH_BUTTON_LABEL')}>
|
|
255
|
+
|
|
256
|
+
</label>
|
|
233
257
|
<Button
|
|
234
258
|
disabled={searchDisabled}
|
|
235
259
|
onClick={(e: React.MouseEvent<HTMLElement>) => {
|
|
@@ -237,6 +261,7 @@ export function QueryControls({
|
|
|
237
261
|
setQueryExpression(true);
|
|
238
262
|
}}
|
|
239
263
|
id="h-matcher-search-button"
|
|
264
|
+
{...testId('SEARCH_BUTTON')}
|
|
240
265
|
>
|
|
241
266
|
Search
|
|
242
267
|
</Button>
|
|
@@ -17,6 +17,7 @@ import {RpcError} from '@protobuf-ts/runtime-rpc';
|
|
|
17
17
|
|
|
18
18
|
import {ProfileType, ProfileTypesResponse} from '@parca/client';
|
|
19
19
|
import {Select, type SelectElement} from '@parca/components';
|
|
20
|
+
import {testId} from '@parca/test-utils';
|
|
20
21
|
|
|
21
22
|
interface WellKnownProfile {
|
|
22
23
|
name: string;
|
|
@@ -197,6 +198,7 @@ const ProfileTypeSelector = ({
|
|
|
197
198
|
loading={loading}
|
|
198
199
|
className="bg-white h-profile-type-dropdown"
|
|
199
200
|
disabled={disabled}
|
|
201
|
+
{...testId('PROFILE_TYPE_SELECTOR')}
|
|
200
202
|
/>
|
|
201
203
|
);
|
|
202
204
|
};
|
|
@@ -168,7 +168,11 @@ const numberMatchTypeItems: SelectItem[] = [
|
|
|
168
168
|
},
|
|
169
169
|
];
|
|
170
170
|
|
|
171
|
-
|
|
171
|
+
export interface ProfileFiltersProps {
|
|
172
|
+
readOnly?: boolean;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const ProfileFilters = ({readOnly = false}: ProfileFiltersProps = {}): JSX.Element => {
|
|
172
176
|
const {profileSource} = useProfileViewContext();
|
|
173
177
|
const currentProfileType = profileSource?.ProfileType()?.toString();
|
|
174
178
|
const filterTypeItems = getFilterTypeItems(currentProfileType);
|
|
@@ -213,6 +217,7 @@ const ProfileFilters = (): JSX.Element => {
|
|
|
213
217
|
items={filterTypeItems}
|
|
214
218
|
selectedKey={filter.type}
|
|
215
219
|
placeholder="Select Filter"
|
|
220
|
+
disabled={readOnly}
|
|
216
221
|
onSelection={key => {
|
|
217
222
|
// Check if this is a preset selection
|
|
218
223
|
if (isPresetKey(key)) {
|
|
@@ -246,10 +251,13 @@ const ProfileFilters = (): JSX.Element => {
|
|
|
246
251
|
}
|
|
247
252
|
}}
|
|
248
253
|
className={cx(
|
|
249
|
-
'
|
|
250
|
-
|
|
251
|
-
|
|
254
|
+
'gap-0 focus:z-50 focus:relative focus:outline-1',
|
|
255
|
+
readOnly ? '' : 'pr-1',
|
|
256
|
+
readOnly && isPresetFilter ? 'rounded-md' : 'rounded-l-md rounded-r-none',
|
|
257
|
+
!readOnly && (isPresetFilter ? 'rounded-r-none border-r-0' : 'rounded-r-none'),
|
|
258
|
+
readOnly ? 'w-auto' : filter.type != null ? 'border-r-0 w-auto' : 'w-32'
|
|
252
259
|
)}
|
|
260
|
+
hideCaretDropdown={readOnly}
|
|
253
261
|
/>
|
|
254
262
|
|
|
255
263
|
{filter.type != null && !isPresetFilter && (
|
|
@@ -257,6 +265,7 @@ const ProfileFilters = (): JSX.Element => {
|
|
|
257
265
|
<Select
|
|
258
266
|
items={fieldItems}
|
|
259
267
|
selectedKey={filter.field ?? ''}
|
|
268
|
+
disabled={readOnly}
|
|
260
269
|
onSelection={key => {
|
|
261
270
|
const newField = key as ProfileFilter['field'];
|
|
262
271
|
const isNewFieldNumber = newField === 'address' || newField === 'line_number';
|
|
@@ -272,21 +281,31 @@ const ProfileFilters = (): JSX.Element => {
|
|
|
272
281
|
updateFilter(filter.id, {field: newField});
|
|
273
282
|
}
|
|
274
283
|
}}
|
|
275
|
-
className=
|
|
284
|
+
className={cx(
|
|
285
|
+
'rounded-none border-r-0 w-32 gap-0 focus:z-50 focus:relative focus:outline-1',
|
|
286
|
+
readOnly ? '' : 'pr-1'
|
|
287
|
+
)}
|
|
288
|
+
hideCaretDropdown={readOnly}
|
|
276
289
|
/>
|
|
277
290
|
|
|
278
291
|
<Select
|
|
279
292
|
items={matchTypeItems}
|
|
280
293
|
selectedKey={filter.matchType ?? ''}
|
|
294
|
+
disabled={readOnly}
|
|
281
295
|
onSelection={key =>
|
|
282
296
|
updateFilter(filter.id, {matchType: key as ProfileFilter['matchType']})
|
|
283
297
|
}
|
|
284
|
-
className=
|
|
298
|
+
className={cx(
|
|
299
|
+
'rounded-none border-r-0 gap-0 focus:z-50 focus:relative focus:outline-1',
|
|
300
|
+
readOnly ? '' : 'pr-1'
|
|
301
|
+
)}
|
|
302
|
+
hideCaretDropdown={readOnly}
|
|
285
303
|
/>
|
|
286
304
|
|
|
287
305
|
<Input
|
|
288
306
|
placeholder="Value"
|
|
289
307
|
value={filter.value}
|
|
308
|
+
disabled={readOnly}
|
|
290
309
|
onChange={e => updateFilter(filter.id, {value: e.target.value})}
|
|
291
310
|
onKeyDown={handleKeyDown}
|
|
292
311
|
className="rounded-none w-36 text-sm focus:outline-1"
|
|
@@ -294,40 +313,44 @@ const ProfileFilters = (): JSX.Element => {
|
|
|
294
313
|
</>
|
|
295
314
|
)}
|
|
296
315
|
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
316
|
+
{!readOnly && (
|
|
317
|
+
<Button
|
|
318
|
+
variant="neutral"
|
|
319
|
+
onClick={() => {
|
|
320
|
+
// If we're displaying local filters and this is the last one, reset everything
|
|
321
|
+
if (localFilters.length > 0 && localFilters.length === 1) {
|
|
322
|
+
resetFilters();
|
|
323
|
+
}
|
|
324
|
+
// If we're displaying applied filters and this is the last one, reset everything
|
|
325
|
+
else if (localFilters.length === 0 && filtersToRender.length === 1) {
|
|
326
|
+
resetFilters();
|
|
327
|
+
}
|
|
328
|
+
// Otherwise, just remove this specific filter
|
|
329
|
+
else {
|
|
330
|
+
removeFilter(filter.id);
|
|
331
|
+
}
|
|
332
|
+
}}
|
|
333
|
+
className={cx(
|
|
334
|
+
'h-[38px] p-3',
|
|
335
|
+
filter.type != null
|
|
336
|
+
? 'rounded-none rounded-r-md'
|
|
337
|
+
: 'rounded-l-none rounded-r-md'
|
|
338
|
+
)}
|
|
339
|
+
>
|
|
340
|
+
<Icon icon="mdi:close" className="h-4 w-4" />
|
|
341
|
+
</Button>
|
|
342
|
+
)}
|
|
320
343
|
</div>
|
|
321
344
|
);
|
|
322
345
|
})}
|
|
323
346
|
|
|
324
|
-
{localFilters.length > 0 && (
|
|
347
|
+
{!readOnly && localFilters.length > 0 && (
|
|
325
348
|
<Button variant="neutral" onClick={addFilter} className="p-3 h-[38px]">
|
|
326
349
|
<Icon icon="mdi:filter-plus-outline" className="h-4 w-4" />
|
|
327
350
|
</Button>
|
|
328
351
|
)}
|
|
329
352
|
|
|
330
|
-
{localFilters.length === 0 && (appliedFilters?.length ?? 0) === 0 && (
|
|
353
|
+
{!readOnly && localFilters.length === 0 && (appliedFilters?.length ?? 0) === 0 && (
|
|
331
354
|
<Button variant="neutral" onClick={addFilter} className="flex items-center gap-2">
|
|
332
355
|
<Icon icon="mdi:filter-outline" className="h-4 w-4" />
|
|
333
356
|
<span>Filter</span>
|
|
@@ -335,7 +358,7 @@ const ProfileFilters = (): JSX.Element => {
|
|
|
335
358
|
)}
|
|
336
359
|
</div>
|
|
337
360
|
|
|
338
|
-
{localFilters.length > 0 && (
|
|
361
|
+
{!readOnly && localFilters.length > 0 && (
|
|
339
362
|
<Button
|
|
340
363
|
variant="primary"
|
|
341
364
|
onClick={onApplyFilters}
|
|
@@ -18,6 +18,7 @@ import {Icon} from '@iconify/react';
|
|
|
18
18
|
import {QueryServiceClient} from '@parca/client';
|
|
19
19
|
import {Button} from '@parca/components';
|
|
20
20
|
import {ProfileType} from '@parca/parser';
|
|
21
|
+
import {testId} from '@parca/test-utils';
|
|
21
22
|
|
|
22
23
|
import {CurrentPathFrame} from '../../../ProfileFlameGraph/FlameGraphArrow/utils';
|
|
23
24
|
import {ProfileSource} from '../../../ProfileSource';
|
|
@@ -87,6 +88,7 @@ export const FlameGraphToolbar: FC<FlameGraphToolbarProps> = ({curPath, setNewCu
|
|
|
87
88
|
onClick={() => setNewCurPath([])}
|
|
88
89
|
disabled={curPath.length === 0}
|
|
89
90
|
id="h-reset-graph"
|
|
91
|
+
{...testId('FLAMEGRAPH_RESET_BUTTON')}
|
|
90
92
|
>
|
|
91
93
|
Reset graph
|
|
92
94
|
<Icon icon="system-uicons:reset" width={20} />
|
|
@@ -20,6 +20,7 @@ import cx from 'classnames';
|
|
|
20
20
|
import {QueryServiceClient} from '@parca/client';
|
|
21
21
|
import {useGrpcMetadata} from '@parca/components';
|
|
22
22
|
import {Query} from '@parca/parser';
|
|
23
|
+
import {testId} from '@parca/test-utils';
|
|
23
24
|
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
24
25
|
|
|
25
26
|
import {LabelProvider, useLabels} from '../contexts/SimpleMatchersLabelContext';
|
|
@@ -356,9 +357,10 @@ const SimpleMatchers = ({
|
|
|
356
357
|
<div
|
|
357
358
|
className={`flex items-center gap-3 ${maxWidthInPixels} w-full flex-wrap`}
|
|
358
359
|
id="simple-matchers"
|
|
360
|
+
{...testId('SIMPLE_MATCHERS_CONTAINER')}
|
|
359
361
|
>
|
|
360
362
|
{visibleRows.map((row, index) => (
|
|
361
|
-
<div key={index} className="flex items-center">
|
|
363
|
+
<div key={index} className="flex items-center" {...testId('SIMPLE_MATCHER_ROW')}>
|
|
362
364
|
<Select
|
|
363
365
|
items={labelNameOptions}
|
|
364
366
|
onSelection={value => handleUpdateRow(index, 'labelName', value)}
|
|
@@ -367,12 +369,14 @@ const SimpleMatchers = ({
|
|
|
367
369
|
className="rounded-tr-none rounded-br-none ring-0 focus:ring-0 outline-none"
|
|
368
370
|
loading={labelNamesLoading}
|
|
369
371
|
searchable={true}
|
|
372
|
+
{...testId('LABEL_NAME_SELECT')}
|
|
370
373
|
/>
|
|
371
374
|
<Select
|
|
372
375
|
items={operatorOptions}
|
|
373
376
|
onSelection={value => handleUpdateRow(index, 'operator', value)}
|
|
374
377
|
selectedKey={row.operator}
|
|
375
378
|
className="rounded-none ring-0 focus:ring-0 outline-none"
|
|
379
|
+
{...testId('OPERATOR_SELECT')}
|
|
376
380
|
/>
|
|
377
381
|
<Select
|
|
378
382
|
items={transformLabelsForSelect(row.labelValues)}
|
|
@@ -388,12 +392,14 @@ const SimpleMatchers = ({
|
|
|
388
392
|
loading={row.isLoading}
|
|
389
393
|
onButtonClick={() => handleLabelValueClick(index)}
|
|
390
394
|
editable={isRowRegex(row)}
|
|
395
|
+
{...testId('LABEL_VALUE_SELECT')}
|
|
391
396
|
/>
|
|
392
397
|
<button
|
|
393
398
|
onClick={() => removeRow(index)}
|
|
394
399
|
className={cx(
|
|
395
400
|
'p-2 border-gray-200 border rounded rounded-tl-none rounded-bl-none focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900'
|
|
396
401
|
)}
|
|
402
|
+
{...testId('REMOVE_MATCHER_BUTTON')}
|
|
397
403
|
>
|
|
398
404
|
<Icon icon="carbon:close" className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
|
399
405
|
</button>
|
|
@@ -404,6 +410,7 @@ const SimpleMatchers = ({
|
|
|
404
410
|
<button
|
|
405
411
|
onClick={() => setShowAll(!showAll)}
|
|
406
412
|
className="mr-2 px-3 py-1 text-sm font-medium text-gray-700 dark:text-gray-200 bg-gray-100 rounded-md hover:bg-gray-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:bg-gray-900"
|
|
413
|
+
{...testId(showAll ? 'SHOW_LESS_BUTTON' : 'SHOW_MORE_BUTTON')}
|
|
407
414
|
>
|
|
408
415
|
{showAll ? 'Show less' : `Show ${hiddenRowsCount} more`}
|
|
409
416
|
</button>
|
|
@@ -412,6 +419,7 @@ const SimpleMatchers = ({
|
|
|
412
419
|
<button
|
|
413
420
|
onClick={addNewRow}
|
|
414
421
|
className="p-2 border-gray-200 dark:bg-gray-900 dark:border-gray-600 border rounded focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
|
422
|
+
{...testId('ADD_MATCHER_BUTTON')}
|
|
415
423
|
>
|
|
416
424
|
<Icon icon="material-symbols:add" className="h-5 w-5 text-gray-400" aria-hidden="true" />
|
|
417
425
|
</button>
|
|
@@ -19,6 +19,7 @@ import cx from 'classnames';
|
|
|
19
19
|
import {QueryServiceClient} from '@parca/client';
|
|
20
20
|
import {useGrpcMetadata} from '@parca/components';
|
|
21
21
|
import {Query} from '@parca/parser';
|
|
22
|
+
import {testId} from '@parca/test-utils';
|
|
22
23
|
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
23
24
|
|
|
24
25
|
import CustomSelect, {SelectItem} from '../SimpleMatchers/Select';
|
|
@@ -168,7 +169,7 @@ const ViewMatchers: React.FC<Props> = ({
|
|
|
168
169
|
}, []);
|
|
169
170
|
|
|
170
171
|
return (
|
|
171
|
-
<div className="flex flex-wrap gap-2">
|
|
172
|
+
<div className="flex flex-wrap gap-2" {...testId('VIEW_MATCHERS_CONTAINER')}>
|
|
172
173
|
{labelNames.map(labelName => (
|
|
173
174
|
<div key={labelName} className="flex items-center">
|
|
174
175
|
<div className="relative border shadow-sm px-4 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 text-sm flex gap-2 items-center justify-between bg-gray-100 dark:bg-gray-700 rounded-l-md border-gray-300 dark:border-gray-600">
|
package/src/index.tsx
CHANGED
|
@@ -26,6 +26,9 @@ export * from './ProfileTypeSelector';
|
|
|
26
26
|
export * from './SourceView';
|
|
27
27
|
export * from './ProfileMetricsGraph';
|
|
28
28
|
|
|
29
|
+
export {default as ProfileFilters} from './ProfileView/components/ProfileFilters';
|
|
30
|
+
export {useProfileFiltersUrlState} from './ProfileView/components/ProfileFilters/useProfileFiltersUrlState';
|
|
31
|
+
|
|
29
32
|
export const DEFAULT_PROFILE_EXPLORER_PARAM_VALUES = {
|
|
30
33
|
dashboard_items: 'flamegraph',
|
|
31
34
|
};
|