@parca/profile 0.19.75 → 0.19.76

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 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.19.76](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.75...@parca/profile@0.19.76) (2025-11-19)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
6
10
  ## [0.19.75](https://github.com/parca-dev/parca/compare/@parca/profile@0.19.74...@parca/profile@0.19.75) (2025-11-18)
7
11
 
8
12
  **Note:** Version bump only for package @parca/profile
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/MetricsGraph/UtilizationMetrics/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EACL,aAAa,EAId,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAC,KAAK,kBAAkB,IAAI,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAI9E,UAAU,WAAW;IACnB,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAYD,KAAK,KAAK,GAAG,WAAW,GAAG;IACzB,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,KACvE,IAAI,CAAC;IACV,sBAAsB,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,KAAK,IAAI,CAAC;CAChF,CAAC;AAyTF,QAAA,MAAM,kBAAkB,GAAI,6KAWzB,KAAK,KAAG,GAAG,CAAC,OAwCd,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/MetricsGraph/UtilizationMetrics/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EACL,aAAa,EAId,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EAAC,KAAK,kBAAkB,IAAI,YAAY,EAAC,MAAM,uBAAuB,CAAC;AAI9E,UAAU,WAAW;IACnB,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,iBAAiB,EAAE,MAAM,CAAC;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/C;AAYD,KAAK,KAAK,GAAG,WAAW,GAAG;IACzB,IAAI,EAAE,YAAY,EAAE,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,eAAe,CAAC,EAAE,CAChB,MAAM,EAAE;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,GAAG,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,KACvE,IAAI,CAAC;IACV,sBAAsB,CAAC,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC;QAAC,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAC,CAAC,KAAK,IAAI,CAAC;CAChF,CAAC;AA4TF,QAAA,MAAM,kBAAkB,GAAI,6KAWzB,KAAK,KAAG,GAAG,CAAC,OAwCd,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
@@ -122,7 +122,10 @@ const _getYAxisUnit = (name) => {
122
122
  };
123
123
  const RawUtilizationMetrics = ({ data, originalData, setTimeRange, width, height, margin, humanReadableName, from, to, yAxisUnit, contextMenuItems, onSeriesClick, }) => {
124
124
  const { timezone } = useParcaContext();
125
- return (_jsx(MetricsGraph, { data: data, from: from, to: to, setTimeRange: setTimeRange, onSampleClick: closestPoint => {
125
+ return (_jsx(MetricsGraph, { data: data.map((val, idx) => ({
126
+ ...val,
127
+ highlighted: originalData?.[idx]?.isSelected ?? false,
128
+ })), from: from, to: to, setTimeRange: setTimeRange, onSampleClick: closestPoint => {
126
129
  if (onSeriesClick != null) {
127
130
  onSeriesClick(closestPoint.seriesIndex);
128
131
  }
@@ -29,6 +29,7 @@ export interface HighlightedSeries {
29
29
  export interface Series {
30
30
  id: string;
31
31
  values: Array<[number, number]>;
32
+ highlighted?: boolean;
32
33
  }
33
34
  declare const MetricsGraph: ({ data, from, to, onSampleClick, setTimeRange, yAxisLabel, yAxisUnit, width, height, margin, selectedPoint, contextMenuItems, renderTooltipContent, }: Props) => JSX.Element;
34
35
  export default MetricsGraph;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MetricsGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgE,MAAM,OAAO,CAAC;AAOrF,OAAO,EAAC,aAAa,EAAkB,MAAM,mBAAmB,CAAC;AAMjE,OAA2B,EACzB,eAAe,EACf,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAI9B,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,CAAC,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C,oBAAoB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CACrF;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;CACjC;AAED,QAAA,MAAM,YAAY,GAAI,uJAcnB,KAAK,KAAG,GAAG,CAAC,OA+Bd,CAAC;AAEF,eAAe,YAAY,CAAC;AAC5B,YAAY,EAAC,wBAAwB,EAAE,eAAe,EAAE,kBAAkB,EAAC,CAAC;AAE5E,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAKnD,CAAC;AAKF,eAAO,MAAM,eAAe,GAAI,uJAc7B,KAAK,KAAG,GAAG,CAAC,OA6ad,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MetricsGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAgE,MAAM,OAAO,CAAC;AAOrF,OAAO,EAAC,aAAa,EAAkB,MAAM,mBAAmB,CAAC;AAMjE,OAA2B,EACzB,eAAe,EACf,wBAAwB,EACxB,kBAAkB,EACnB,MAAM,sBAAsB,CAAC;AAI9B,UAAU,KAAK;IACb,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,CAAC,YAAY,EAAE,WAAW,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,aAAa,CAAC,EAAE,WAAW,GAAG,IAAI,CAAC;IACnC,gBAAgB,CAAC,EAAE,wBAAwB,EAAE,CAAC;IAC9C,oBAAoB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,KAAK,KAAK,CAAC,SAAS,CAAC;CACrF;AAED,MAAM,WAAW,WAAW;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,MAAM,WAAW,MAAM;IACrB,EAAE,EAAE,MAAM,CAAC;IACX,MAAM,EAAE,KAAK,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED,QAAA,MAAM,YAAY,GAAI,uJAcnB,KAAK,KAAG,GAAG,CAAC,OA+Bd,CAAC;AAEF,eAAe,YAAY,CAAC;AAC5B,YAAY,EAAC,wBAAwB,EAAE,eAAe,EAAE,kBAAkB,EAAC,CAAC;AAE5E,eAAO,MAAM,UAAU,GAAI,OAAO,MAAM,KAAG,MAAM,GAAG,IAKnD,CAAC;AAKF,eAAO,MAAM,eAAe,GAAI,uJAc7B,KAAK,KAAG,GAAG,CAAC,OAibd,CAAC"}
@@ -85,7 +85,10 @@ export const RawMetricsGraph = ({ data, from, to, onSampleClick, setTimeRange, y
85
85
  }, [series]);
86
86
  const l = d3.line(d => xScale(d[0]), d => yScale(d[1]));
87
87
  const closestPoint = useMemo(() => {
88
- // Return the closest point as the highlighted point
88
+ // Guard against empty series
89
+ if (series.length === 0) {
90
+ return null;
91
+ }
89
92
  const closestPointPerSeries = series.map(function (s) {
90
93
  const distances = s.values.map(d => {
91
94
  const x = xScale(d[0]) + margin / 2; // d[0] is timestamp_ms
@@ -219,7 +222,8 @@ export const RawMetricsGraph = ({ data, from, to, onSampleClick, setTimeRange, y
219
222
  transform: `translate(0, ${yScale(d)})`, children: [_jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x2: -6 }), _jsx("text", { fill: "currentColor", x: -9, dy: '0.32em', children: valueFormatter(d, yAxisUnit, decimals) })] }, `tick-${i}`), _jsx("g", { children: _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(from), x2: xScale(to), y1: yScale(d), y2: yScale(d) }) }, `grid-${i}`)] }, `${i.toString()}-${d.toString()}`));
220
223
  }), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: 0, x2: 0, y1: 0, y2: height - margin }), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(to), x2: xScale(to), y1: 0, y2: height - margin }), _jsx("g", { transform: `translate(${-margin}, ${(height - margin) / 2}) rotate(270)`, children: _jsx("text", { fill: "currentColor", dy: "-0.7em", className: "text-sm capitalize", textAnchor: "middle", children: yAxisLabel }) })] }), _jsxs("g", { className: "x axis", fill: "none", fontSize: "10", textAnchor: "middle", transform: `translate(0,${height - margin})`, children: [xScale.ticks(5).map((d, i) => (_jsxs(Fragment, { children: [_jsxs("g", { className: "tick",
221
224
  /* eslint-disable-next-line @typescript-eslint/restrict-template-expressions */
222
- transform: `translate(${xScale(d)}, 0)`, children: [_jsx("line", { y2: 6, className: "stroke-gray-300 dark:stroke-gray-500" }), _jsx("text", { fill: "currentColor", dy: ".71em", y: 9, children: formatDate(d, formatForTimespan(from, to), timezone) })] }, `tick-${i}`), _jsx("g", { children: _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(d), x2: xScale(d), y1: 0, y2: -height + margin }) }, `grid-${i}`)] }, `${i.toString()}-${d.toString()}`))), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: 0, x2: graphWidth, y1: 0, y2: 0 }), _jsx("g", { transform: `translate(${(width - 2.5 * margin) / 2}, ${margin / 2})`, children: _jsx("text", { fill: "currentColor", dy: ".71em", y: 5, className: "text-sm", children: "Time" }) })] }), _jsx("g", { className: "lines fill-transparent", transform: graphTransform, width: graphWidth - 100, children: series.map((s, i) => (_jsx("g", { className: "line", children: _jsx(MetricsSeries, { data: s, line: l, color: color(s.id), strokeWidth: hovering && highlighted != null && i === highlighted.seriesIndex
225
+ transform: `translate(${xScale(d)}, 0)`, children: [_jsx("line", { y2: 6, className: "stroke-gray-300 dark:stroke-gray-500" }), _jsx("text", { fill: "currentColor", dy: ".71em", y: 9, children: formatDate(d, formatForTimespan(from, to), timezone) })] }, `tick-${i}`), _jsx("g", { children: _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: xScale(d), x2: xScale(d), y1: 0, y2: -height + margin }) }, `grid-${i}`)] }, `${i.toString()}-${d.toString()}`))), _jsx("line", { className: "stroke-gray-300 dark:stroke-gray-500", x1: 0, x2: graphWidth, y1: 0, y2: 0 }), _jsx("g", { transform: `translate(${(width - 2.5 * margin) / 2}, ${margin / 2})`, children: _jsx("text", { fill: "currentColor", dy: ".71em", y: 5, className: "text-sm", children: "Time" }) })] }), _jsx("g", { className: "lines fill-transparent", transform: graphTransform, width: graphWidth - 100, children: series.map((s, i) => (_jsx("g", { className: "line", children: _jsx(MetricsSeries, { data: s, line: l, color: color(s.id), strokeWidth: (hovering && highlighted != null && i === highlighted.seriesIndex) ||
226
+ s.highlighted === true
223
227
  ? lineStrokeHover
224
228
  : lineStroke, xScale: xScale, yScale: yScale }) }, s.id))) }), hovering && highlighted != null && (_jsx("g", { className: "circle-group", ref: metricPointRef, style: { fill: color(series[highlighted.seriesIndex]?.id ?? '0') }, transform: graphTransform, children: _jsx(MetricsCircle, { cx: highlighted.x, cy: highlighted.y }) })), selected != null && (_jsx("g", { className: "circle-group", style: selected?.seriesIndex != null
225
229
  ? { fill: color(series[selected.seriesIndex]?.id ?? '0') }
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsGraphSection.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/MetricsGraphSection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAQ,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACxD,OAAO,EAAC,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAKpC,OAAO,EAAC,cAAc,EAAE,KAAK,kBAAkB,IAAI,sBAAsB,EAAC,MAAM,SAAS,CAAC;AAE1F,UAAU,wBAAwB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gCAAgC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChF,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3E,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,kBAAkB,CAAC,EAAE,KAAK,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;QAC1B,IAAI,EAAE,sBAAsB,EAAE,CAAC;KAChC,CAAC,CAAC;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,yBAAyB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,mBAAmB,CAAC,EAClC,gBAAgB,EAChB,gCAAgC,EAChC,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,KAAK,EACL,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,KAAK,EACL,qBAAqB,EACrB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,GAC1B,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CA8MxC"}
1
+ {"version":3,"file":"MetricsGraphSection.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/MetricsGraphSection.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAQ,kBAAkB,EAAC,MAAM,eAAe,CAAC;AACxD,OAAO,EAAC,aAAa,EAAmB,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAEpC,OAAO,EAAC,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAKpC,OAAO,EAAC,cAAc,EAAE,KAAK,kBAAkB,IAAI,sBAAsB,EAAC,MAAM,SAAS,CAAC;AAE1F,UAAU,wBAAwB;IAChC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gCAAgC,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3D,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,kBAAkB,CAAC;IAChC,qBAAqB,EAAE,MAAM,CAAC;IAC9B,qBAAqB,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IACtD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IAChF,KAAK,EAAE,KAAK,CAAC;IACb,qBAAqB,EAAE,CAAC,eAAe,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IAC3E,kBAAkB,EAAE,CAAC,QAAQ,CAAC,EAAE,OAAO,KAAK,IAAI,CAAC;IACjD,kBAAkB,CAAC,EAAE,KAAK,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;QAC1B,IAAI,EAAE,sBAAsB,EAAE,CAAC;KAChC,CAAC,CAAC;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,yBAAyB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED,wBAAgB,mBAAmB,CAAC,EAClC,gBAAgB,EAChB,gCAAgC,EAChC,WAAW,EACX,cAAc,EACd,gBAAgB,EAChB,SAAS,EACT,KAAK,EACL,mBAAmB,EACnB,WAAW,EACX,qBAAqB,EACrB,qBAAqB,EACrB,WAAW,EACX,mBAAmB,EACnB,KAAK,EACL,qBAAqB,EACrB,kBAAkB,EAClB,yBAAyB,EACzB,yBAAyB,GAC1B,EAAE,wBAAwB,GAAG,GAAG,CAAC,OAAO,CA4MxC"}
@@ -91,12 +91,12 @@ export function MetricsGraphSection({ showMetricsGraph, setDisplayHideMetricsGra
91
91
  return (_jsxs("div", { children: [utilizationMetrics.map(({ name, humanReadableName, data }) => {
92
92
  if (name !== 'gpu_pcie_throughput_transmit_bytes' &&
93
93
  name !== 'gpu_pcie_throughput_receive_bytes') {
94
- return (_jsx(_Fragment, { children: _jsx(UtilizationMetricsGraph, { data: data, setTimeRange: handleTimeRangeChange, utilizationMetricsLoading: utilizationMetricsLoading, humanReadableName: humanReadableName, from: querySelection.from, to: querySelection.to, yAxisUnit: "percentage", addLabelMatcher: addLabelMatcher, onSeriesClick: seriesIndex => {
95
- // For generic UtilizationMetrics, just pass the series index
96
- if (onUtilizationSeriesSelect != null) {
97
- onUtilizationSeriesSelect(seriesIndex);
98
- }
99
- } }, name) }));
94
+ return (_jsx(UtilizationMetricsGraph, { data: data, setTimeRange: handleTimeRangeChange, utilizationMetricsLoading: utilizationMetricsLoading, humanReadableName: humanReadableName, from: querySelection.from, to: querySelection.to, yAxisUnit: "percentage", addLabelMatcher: addLabelMatcher, onSeriesClick: seriesIndex => {
95
+ // For generic UtilizationMetrics, just pass the series index
96
+ if (onUtilizationSeriesSelect != null) {
97
+ onUtilizationSeriesSelect(seriesIndex);
98
+ }
99
+ } }, name));
100
100
  }
101
101
  return null;
102
102
  }), throughputMetrics.length > 0 && (_jsx(AreaChart, { transmitData: throughputMetrics.find(metric => metric.name === 'gpu_pcie_throughput_transmit_bytes')
@@ -53,6 +53,7 @@ interface ProfileSelectorProps extends ProfileSelectorFeatures {
53
53
  utilizationMetricsLoading?: boolean;
54
54
  utilizationLabels?: UtilizationLabels;
55
55
  onUtilizationSeriesSelect?: (seriesIndex: number) => void;
56
+ onSearchHook?: () => void;
56
57
  }
57
58
  export interface IProfileTypesResult {
58
59
  loading: boolean;
@@ -60,6 +61,6 @@ export interface IProfileTypesResult {
60
61
  error?: RpcError;
61
62
  }
62
63
  export declare const useProfileTypes: (client: QueryServiceClient, start?: number, end?: number) => IProfileTypesResult;
63
- declare const ProfileSelector: ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector, disableExplorativeQuerying, setDisplayHideMetricsGraphButton, suffix, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, onUtilizationSeriesSelect, }: ProfileSelectorProps) => JSX.Element;
64
+ declare const ProfileSelector: ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph, showSumBySelector, showProfileTypeSelector, disableExplorativeQuerying, setDisplayHideMetricsGraphButton, suffix, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, onUtilizationSeriesSelect, onSearchHook, }: ProfileSelectorProps) => JSX.Element;
64
65
  export default ProfileSelector;
65
66
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAW5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAW/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE;QACR,MAAM,EAAE,KAAK,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;IACF,OAAO,EAAE,KAAK,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,kBAAkB,CAAC,EAAE,KAAK,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;QAC1B,IAAI,EAAE,kBAAkB,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,yBAAyB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CAC3D;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,6SAgBtB,oBAAoB,KAAG,GAAG,CAAC,OAwN7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAE,cAAc,EAAoD,MAAM,OAAO,CAAC;AAElG,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAsB,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAW/E,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,EAAE,MAAM,EAAE,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,uBAAuB;IAC/B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,uBAAuB,CAAC,EAAE,OAAO,CAAC;IAClC,0BAA0B,CAAC,EAAE,OAAO,CAAC;IACrC,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,kBAAkB;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,QAAQ,EAAE;QACR,MAAM,EAAE,KAAK,CAAC;YACZ,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;IACF,OAAO,EAAE,KAAK,CAAC;QACb,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;KACf,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,iBAAiB;IAChC,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;IACjC,2BAA2B,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACjE,sBAAsB,CAAC,EAAE,MAAM,EAAE,CAAC;IAClC,4BAA4B,CAAC,EAAE,OAAO,CAAC;CACxC;AAED,UAAU,oBAAqB,SAAQ,uBAAuB;IAC5D,WAAW,EAAE,kBAAkB,CAAC;IAChC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,gCAAgC,CAAC,EAAE,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;IACrE,MAAM,CAAC,EAAE,IAAI,GAAG,IAAI,CAAC;IACrB,kBAAkB,CAAC,EAAE,KAAK,CAAC;QACzB,IAAI,EAAE,MAAM,CAAC;QACb,iBAAiB,EAAE,MAAM,CAAC;QAC1B,IAAI,EAAE,kBAAkB,EAAE,CAAC;KAC5B,CAAC,CAAC;IACH,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,iBAAiB,CAAC,EAAE,iBAAiB,CAAC;IACtC,yBAAyB,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC3B;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,KAAK,CAAC,EAAE,QAAQ,CAAC;CAClB;AAED,eAAO,MAAM,eAAe,GAC1B,QAAQ,kBAAkB,EAC1B,QAAQ,MAAM,EACd,MAAM,MAAM,KACX,mBAsBF,CAAC;AAEF,QAAA,MAAM,eAAe,GAAI,2TAiBtB,oBAAoB,KAAG,GAAG,CAAC,OA8N7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -12,7 +12,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
15
- import { DateTimeRange, IconButton, useGrpcMetadata, useParcaContext, useURLState, } from '@parca/components';
15
+ import { DateTimeRange, IconButton, useGrpcMetadata, useParcaContext, useURLState, useURLStateBatch, } from '@parca/components';
16
16
  import { CloseIcon } from '@parca/icons';
17
17
  import { Query } from '@parca/parser';
18
18
  import { TEST_IDS, testId } from '@parca/test-utils';
@@ -45,10 +45,11 @@ export const useProfileTypes = (client, start, end) => {
45
45
  });
46
46
  return { loading: isLoading, data, error: error };
47
47
  };
48
- const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true, disableExplorativeQuerying = false, setDisplayHideMetricsGraphButton, suffix, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, onUtilizationSeriesSelect, }) => {
48
+ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, comparing, navigateTo, showMetricsGraph = true, showSumBySelector = true, showProfileTypeSelector = true, disableExplorativeQuerying = false, setDisplayHideMetricsGraphButton, suffix, utilizationMetrics, utilizationMetricsLoading, utilizationLabels, onUtilizationSeriesSelect, onSearchHook, }) => {
49
49
  const { heightStyle } = useMetricsGraphDimensions(comparing, utilizationMetrics != null);
50
50
  const { viewComponent } = useParcaContext();
51
51
  const [queryBrowserMode, setQueryBrowserMode] = useURLState('query_browser_mode');
52
+ const batchUpdates = useURLStateBatch();
52
53
  // Use the new useQueryState hook - reads directly from URL params
53
54
  const { querySelection, draftSelection, setDraftExpression, setDraftTimeRange, setDraftSumBy, setDraftProfileName, setDraftMatchers, commitDraft, profileSelection, setProfileSelection, sumByLoading, } = useQueryState({ suffix });
54
55
  // Use draft state for local state instead of committed state
@@ -88,23 +89,28 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
88
89
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
89
90
  const selectedProfileName = query.profileName();
90
91
  const setQueryExpression = (updateTs = false) => {
91
- // When updateTs is true, re-evaluate the time range to current values
92
- if (updateTs) {
93
- // Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
94
- const currentFrom = timeRangeSelection.getFromMs(true);
95
- const currentTo = timeRangeSelection.getToMs(true);
96
- const currentRangeKey = timeRangeSelection.getRangeKey();
97
- // Commit with refreshed time range
98
- commitDraft({
99
- from: currentFrom,
100
- to: currentTo,
101
- timeSelection: currentRangeKey,
102
- });
103
- }
104
- else {
105
- // Commit the draft with existing values
106
- commitDraft();
107
- }
92
+ batchUpdates(() => {
93
+ if (onSearchHook != null) {
94
+ onSearchHook();
95
+ }
96
+ // When updateTs is true, re-evaluate the time range to current values
97
+ if (updateTs) {
98
+ // Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
99
+ const currentFrom = timeRangeSelection.getFromMs(true);
100
+ const currentTo = timeRangeSelection.getToMs(true);
101
+ const currentRangeKey = timeRangeSelection.getRangeKey();
102
+ // Commit with refreshed time range
103
+ commitDraft({
104
+ from: currentFrom,
105
+ to: currentTo,
106
+ timeSelection: currentRangeKey,
107
+ });
108
+ }
109
+ else {
110
+ // Commit the draft with existing values
111
+ commitDraft();
112
+ }
113
+ });
108
114
  };
109
115
  const setMatchersString = (matchers) => {
110
116
  // Update draft state only
@@ -114,12 +114,13 @@ export const useQueryState = (options = {}) => {
114
114
  const draftMergeTo = isDelta
115
115
  ? (BigInt(draftTimeRange.getToMs()) * 1000000n).toString()
116
116
  : undefined;
117
+ const finalSumBy = draftSumBy ?? computedSumByFromURL;
117
118
  return {
118
119
  expression: draftExpression ?? defaultExpression,
119
120
  from: draftTimeRange.getFromMs(),
120
121
  to: draftTimeRange.getToMs(),
121
122
  timeSelection: draftTimeRange.getRangeKey(),
122
- sumBy: draftSumBy ?? computedSumByFromURL, // Use draft if set, otherwise fallback to computed
123
+ sumBy: finalSumBy, // Use draft if set, otherwise fallback to computed
123
124
  ...(draftMergeFrom !== undefined &&
124
125
  draftMergeFrom !== '' &&
125
126
  draftMergeTo !== undefined &&
package/dist/useSumBy.js CHANGED
@@ -88,7 +88,7 @@ const getSumByFromParam = (param) => {
88
88
  return undefined;
89
89
  }
90
90
  if (param === '__none__') {
91
- return [];
91
+ return DEFAULT_EMPTY_SUM_BY;
92
92
  }
93
93
  if (typeof param === 'string') {
94
94
  // Handle comma-separated strings (e.g., "comm,node" -> ["comm", "node"])
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.19.75",
3
+ "version": "0.19.76",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@floating-ui/react": "^0.27.12",
@@ -79,5 +79,5 @@
79
79
  "access": "public",
80
80
  "registry": "https://registry.npmjs.org/"
81
81
  },
82
- "gitHead": "bedae1353c29f9903653fd4a063be5c98a563f32"
82
+ "gitHead": "11845257fa22f46033a9c1c5526721619b7aa2b7"
83
83
  }
@@ -201,7 +201,10 @@ const RawUtilizationMetrics = ({
201
201
 
202
202
  return (
203
203
  <MetricsGraph
204
- data={data}
204
+ data={data.map((val, idx) => ({
205
+ ...val,
206
+ highlighted: originalData?.[idx]?.isSelected ?? false,
207
+ }))}
205
208
  from={from}
206
209
  to={to}
207
210
  setTimeRange={setTimeRange}
@@ -63,6 +63,7 @@ export interface HighlightedSeries {
63
63
  export interface Series {
64
64
  id: string; // opaque string used to determine line color
65
65
  values: Array<[number, number]>; // [timestamp_ms, value]
66
+ highlighted?: boolean;
66
67
  }
67
68
 
68
69
  const MetricsGraph = ({
@@ -200,7 +201,10 @@ export const RawMetricsGraph = ({
200
201
  );
201
202
 
202
203
  const closestPoint = useMemo(() => {
203
- // Return the closest point as the highlighted point
204
+ // Guard against empty series
205
+ if (series.length === 0) {
206
+ return null;
207
+ }
204
208
 
205
209
  const closestPointPerSeries = series.map(function (s) {
206
210
  const distances = s.values.map(d => {
@@ -530,7 +534,8 @@ export const RawMetricsGraph = ({
530
534
  line={l}
531
535
  color={color(s.id)}
532
536
  strokeWidth={
533
- hovering && highlighted != null && i === highlighted.seriesIndex
537
+ (hovering && highlighted != null && i === highlighted.seriesIndex) ||
538
+ s.highlighted === true
534
539
  ? lineStrokeHover
535
540
  : lineStroke
536
541
  }
@@ -174,25 +174,23 @@ export function MetricsGraphSection({
174
174
  name !== 'gpu_pcie_throughput_receive_bytes'
175
175
  ) {
176
176
  return (
177
- <>
178
- <UtilizationMetricsGraph
179
- key={name}
180
- data={data}
181
- setTimeRange={handleTimeRangeChange}
182
- utilizationMetricsLoading={utilizationMetricsLoading}
183
- humanReadableName={humanReadableName}
184
- from={querySelection.from}
185
- to={querySelection.to}
186
- yAxisUnit="percentage"
187
- addLabelMatcher={addLabelMatcher}
188
- onSeriesClick={seriesIndex => {
189
- // For generic UtilizationMetrics, just pass the series index
190
- if (onUtilizationSeriesSelect != null) {
191
- onUtilizationSeriesSelect(seriesIndex);
192
- }
193
- }}
194
- />
195
- </>
177
+ <UtilizationMetricsGraph
178
+ key={name}
179
+ data={data}
180
+ setTimeRange={handleTimeRangeChange}
181
+ utilizationMetricsLoading={utilizationMetricsLoading}
182
+ humanReadableName={humanReadableName}
183
+ from={querySelection.from}
184
+ to={querySelection.to}
185
+ yAxisUnit="percentage"
186
+ addLabelMatcher={addLabelMatcher}
187
+ onSeriesClick={seriesIndex => {
188
+ // For generic UtilizationMetrics, just pass the series index
189
+ if (onUtilizationSeriesSelect != null) {
190
+ onUtilizationSeriesSelect(seriesIndex);
191
+ }
192
+ }}
193
+ />
196
194
  );
197
195
  }
198
196
  return null;
@@ -22,6 +22,7 @@ import {
22
22
  useGrpcMetadata,
23
23
  useParcaContext,
24
24
  useURLState,
25
+ useURLStateBatch,
25
26
  } from '@parca/components';
26
27
  import {CloseIcon} from '@parca/icons';
27
28
  import {Query} from '@parca/parser';
@@ -92,6 +93,7 @@ interface ProfileSelectorProps extends ProfileSelectorFeatures {
92
93
  utilizationMetricsLoading?: boolean;
93
94
  utilizationLabels?: UtilizationLabels;
94
95
  onUtilizationSeriesSelect?: (seriesIndex: number) => void;
96
+ onSearchHook?: () => void;
95
97
  }
96
98
 
97
99
  export interface IProfileTypesResult {
@@ -144,10 +146,12 @@ const ProfileSelector = ({
144
146
  utilizationMetricsLoading,
145
147
  utilizationLabels,
146
148
  onUtilizationSeriesSelect,
149
+ onSearchHook,
147
150
  }: ProfileSelectorProps): JSX.Element => {
148
151
  const {heightStyle} = useMetricsGraphDimensions(comparing, utilizationMetrics != null);
149
152
  const {viewComponent} = useParcaContext();
150
153
  const [queryBrowserMode, setQueryBrowserMode] = useURLState('query_browser_mode');
154
+ const batchUpdates = useURLStateBatch();
151
155
 
152
156
  // Use the new useQueryState hook - reads directly from URL params
153
157
  const {
@@ -227,22 +231,27 @@ const ProfileSelector = ({
227
231
  const selectedProfileName = query.profileName();
228
232
 
229
233
  const setQueryExpression = (updateTs = false): void => {
230
- // When updateTs is true, re-evaluate the time range to current values
231
- if (updateTs) {
232
- // Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
233
- const currentFrom = timeRangeSelection.getFromMs(true);
234
- const currentTo = timeRangeSelection.getToMs(true);
235
- const currentRangeKey = timeRangeSelection.getRangeKey();
236
- // Commit with refreshed time range
237
- commitDraft({
238
- from: currentFrom,
239
- to: currentTo,
240
- timeSelection: currentRangeKey,
241
- });
242
- } else {
243
- // Commit the draft with existing values
244
- commitDraft();
245
- }
234
+ batchUpdates(() => {
235
+ if (onSearchHook != null) {
236
+ onSearchHook();
237
+ }
238
+ // When updateTs is true, re-evaluate the time range to current values
239
+ if (updateTs) {
240
+ // Force re-evaluation of time range (important for relative ranges like "last 15 minutes")
241
+ const currentFrom = timeRangeSelection.getFromMs(true);
242
+ const currentTo = timeRangeSelection.getToMs(true);
243
+ const currentRangeKey = timeRangeSelection.getRangeKey();
244
+ // Commit with refreshed time range
245
+ commitDraft({
246
+ from: currentFrom,
247
+ to: currentTo,
248
+ timeSelection: currentRangeKey,
249
+ });
250
+ } else {
251
+ // Commit the draft with existing values
252
+ commitDraft();
253
+ }
254
+ });
246
255
  };
247
256
 
248
257
  const setMatchersString = (matchers: string): void => {
@@ -150,7 +150,6 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
150
150
  draftTo !== '' ? parseInt(draftTo) : defaultTo
151
151
  );
152
152
  }, [draftTimeSelection, draftFrom, draftTo, defaultTimeSelection, defaultFrom, defaultTo]);
153
-
154
153
  // Use combined sumBy hook for fetching labels and computing defaults (based on committed state)
155
154
  const {sumBy: computedSumByFromURL, isLoading: sumBySelectionLoading} = useSumBy(
156
155
  queryClient,
@@ -201,12 +200,13 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
201
200
  ? (BigInt(draftTimeRange.getToMs()) * 1_000_000n).toString()
202
201
  : undefined;
203
202
 
203
+ const finalSumBy = draftSumBy ?? computedSumByFromURL;
204
204
  return {
205
205
  expression: draftExpression ?? defaultExpression,
206
206
  from: draftTimeRange.getFromMs(),
207
207
  to: draftTimeRange.getToMs(),
208
208
  timeSelection: draftTimeRange.getRangeKey(),
209
- sumBy: draftSumBy ?? computedSumByFromURL, // Use draft if set, otherwise fallback to computed
209
+ sumBy: finalSumBy, // Use draft if set, otherwise fallback to computed
210
210
  ...(draftMergeFrom !== undefined &&
211
211
  draftMergeFrom !== '' &&
212
212
  draftMergeTo !== undefined &&
package/src/useSumBy.ts CHANGED
@@ -145,7 +145,7 @@ const getSumByFromParam = (param: string | string[] | undefined): string[] | und
145
145
  }
146
146
 
147
147
  if (param === '__none__') {
148
- return [];
148
+ return DEFAULT_EMPTY_SUM_BY;
149
149
  }
150
150
 
151
151
  if (typeof param === 'string') {