@parca/profile 0.16.413 → 0.16.415

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,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.16.415](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.414...@parca/profile@0.16.415) (2024-07-23)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.414](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.413...@parca/profile@0.16.414) (2024-07-22)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.16.413](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.412...@parca/profile@0.16.413) (2024-07-22)
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":"AAkBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEhF,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAKpC,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;CACrB;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,WAChB,kBAAkB,eACb,MAAM,UACX,MAAM,QACR,MAAM,KACX,aA4BF,CAAC;AAEF,QAAA,MAAM,aAAa,6EAMhB,kBAAkB,KAAG,GAAG,CAAC,OAoL3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/MatchersInput/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EAAgB,cAAc,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEhF,OAAO,EAAC,KAAK,EAAC,MAAM,eAAe,CAAC;AAMpC,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;CACrB;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,WAChB,kBAAkB,eACb,MAAM,UACX,MAAM,QACR,MAAM,KACX,aAyBF,CAAC;AAEF,QAAA,MAAM,aAAa,6EAMhB,kBAAkB,KAAG,GAAG,CAAC,OAoL3B,CAAC;AAEF,eAAe,aAAa,CAAC"}
@@ -17,31 +17,31 @@ import TextareaAutosize from 'react-textarea-autosize';
17
17
  import { useGrpcMetadata } from '@parca/components';
18
18
  import { Query } from '@parca/parser';
19
19
  import { millisToProtoTimestamp, sanitizeLabelValue } from '@parca/utilities';
20
+ import useGrpcQuery from '../useGrpcQuery';
20
21
  import SuggestionsList, { Suggestion, Suggestions } from './SuggestionsList';
21
22
  export const useLabelNames = (client, profileType, start, end) => {
22
- const [loading, setLoading] = useState(true);
23
- const [result, setResult] = useState({});
24
23
  const metadata = useGrpcMetadata();
25
- useEffect(() => {
26
- if (profileType === undefined || profileType === '') {
27
- return;
28
- }
29
- const request = { match: [] };
30
- if (start !== undefined && end !== undefined) {
31
- request.start = millisToProtoTimestamp(start);
32
- request.end = millisToProtoTimestamp(end);
33
- }
34
- if (profileType !== undefined) {
35
- request.profileType = profileType;
36
- }
37
- const call = client.labels(request, { meta: metadata });
38
- setLoading(true);
39
- call.response
40
- .then(response => setResult({ response }))
41
- .catch(error => setResult({ error }))
42
- .finally(() => setLoading(false));
43
- }, [client, metadata, start, end, profileType]);
44
- return { result, loading };
24
+ const { data, isLoading, error } = useGrpcQuery({
25
+ key: ['labelNames', profileType],
26
+ queryFn: async () => {
27
+ const request = { match: [] };
28
+ if (start !== undefined && end !== undefined) {
29
+ request.start = millisToProtoTimestamp(start);
30
+ request.end = millisToProtoTimestamp(end);
31
+ }
32
+ if (profileType !== undefined) {
33
+ request.profileType = profileType;
34
+ }
35
+ const { response } = await client.labels(request, { meta: metadata });
36
+ return response;
37
+ },
38
+ options: {
39
+ enabled: profileType !== undefined && profileType !== '',
40
+ staleTime: 1000 * 60 * 5, // 5 minutes
41
+ keepPreviousData: false,
42
+ },
43
+ });
44
+ return { result: { response: data, error: error }, loading: isLoading };
45
45
  };
46
46
  const MatchersInput = ({ queryClient, setMatchersString, runQuery, currentQuery, profileType, }) => {
47
47
  const inputRef = useRef(null);
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAGjD,OAAO,EAA4B,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAOlF,UAAU,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,GAAG,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAaD,eAAO,MAAM,sBAAsB,eAAgB,MAAM,GAAG,EAAE,KAAG,MAGhE,CAAC;AAgVF,QAAA,MAAM,eAAe,8CAIlB,oBAAoB,KAAG,GAAG,CAAC,OAkB7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAGjD,OAAO,EAA4B,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAQlF,UAAU,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,WAAW,EAAE,GAAG,CAAC;IACjB,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAaD,eAAO,MAAM,sBAAsB,eAAgB,MAAM,GAAG,EAAE,KAAG,MAGhE,CAAC;AAyWF,QAAA,MAAM,eAAe,8CAIlB,oBAAoB,KAAG,GAAG,CAAC,OAkB7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -18,6 +18,7 @@ import { createStore } from '@parca/store';
18
18
  import { capitalizeOnlyFirstLetter } from '@parca/utilities';
19
19
  import { ProfileSelectionFromParams, SuffixParams } from '..';
20
20
  import { useProfileTypes } from '../ProfileSelector';
21
+ import { sumByToParam, useSumByFromParams } from '../useSumBy';
21
22
  import ProfileExplorerCompare from './ProfileExplorerCompare';
22
23
  import ProfileExplorerSingle from './ProfileExplorerSingle';
23
24
  const ErrorContent = ({ errorMessage }) => {
@@ -38,6 +39,19 @@ const sanitizeDateRange = (time_selection_a, from_a, to_a) => {
38
39
  return { time_selection_a: range.getRangeKey(), from_a, to_a };
39
40
  };
40
41
  /* eslint-enable @typescript-eslint/naming-convention */
42
+ const filterEmptyParams = (o) => {
43
+ return Object.fromEntries(Object.entries(o)
44
+ .filter(([_, value]) => value !== '' && value !== undefined && (Array.isArray(value) ? value.length > 0 : true))
45
+ .map(([key, value]) => {
46
+ if (typeof value === 'string') {
47
+ return [key, value];
48
+ }
49
+ if (Array.isArray(value)) {
50
+ return [key, value];
51
+ }
52
+ return [key, value];
53
+ }));
54
+ };
41
55
  const filterSuffix = (o, suffix) => Object.fromEntries(Object.entries(o)
42
56
  .filter(([key]) => !key.endsWith(suffix))
43
57
  .map(([key, value]) => {
@@ -78,6 +92,8 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
78
92
  /* eslint-enable @typescript-eslint/naming-convention */
79
93
  const [profileA, setProfileA] = useState(null);
80
94
  const [profileB, setProfileB] = useState(null);
95
+ const sumByA = useSumByFromParams(sum_by_a);
96
+ const sumByB = useSumByFromParams(sum_by_b);
81
97
  useEffect(() => {
82
98
  const mergeFrom = merge_from_a ?? undefined;
83
99
  const mergeTo = merge_to_a ?? undefined;
@@ -134,7 +150,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
134
150
  from: parseInt(from_a),
135
151
  to: parseInt(to_a),
136
152
  timeSelection: time_selection_a,
137
- sumBy: sum_by_a,
153
+ sumBy: sumByA,
138
154
  };
139
155
  // Show the SingleProfileExplorer when not comparing
140
156
  if (compare_a !== 'true' && compare_b !== 'true') {
@@ -149,17 +165,18 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
149
165
  return navigateTo('/',
150
166
  // Filtering the _a suffix causes us to reset potential profile
151
167
  // selection when running a new query.
152
- {
168
+ filterEmptyParams({
153
169
  ...filterSuffix(queryParams, '_a'),
154
170
  ...{
155
171
  expression_a: encodeURIComponent(q.expression),
156
172
  from_a: q.from.toString(),
157
173
  to_a: q.to.toString(),
158
174
  time_selection_a: q.timeSelection,
175
+ sum_by_a: sumByToParam(q.sumBy),
159
176
  dashboard_items: dashboard_items ?? DEFAULT_DASHBOARD_ITEMS,
160
177
  ...mergeParams,
161
178
  },
162
- });
179
+ }));
163
180
  };
164
181
  const selectProfile = (p) => {
165
182
  queryParams.expression_a = encodeURIComponent(queryParams.expression_a);
@@ -176,7 +193,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
176
193
  from: parseInt(from_b),
177
194
  to: parseInt(to_b),
178
195
  timeSelection: time_selection_b,
179
- sumBy: sum_by_b,
196
+ sumBy: sumByB,
180
197
  };
181
198
  const selectQueryA = (q) => {
182
199
  const mergeParams = q.mergeFrom !== undefined && q.mergeTo !== undefined
@@ -189,7 +206,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
189
206
  return navigateTo('/',
190
207
  // Filtering the _a suffix causes us to reset potential profile
191
208
  // selection when running a new query.
192
- {
209
+ filterEmptyParams({
193
210
  ...filterSuffix(queryParams, '_a'),
194
211
  ...{
195
212
  compare_a: 'true',
@@ -199,11 +216,12 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
199
216
  from_a: q.from.toString(),
200
217
  to_a: q.to.toString(),
201
218
  time_selection_a: q.timeSelection,
219
+ sum_by_a: sumByToParam(q.sumBy),
202
220
  filter_by_function: filter_by_function ?? '',
203
221
  dashboard_items: dashboard_items ?? DEFAULT_DASHBOARD_ITEMS,
204
222
  ...mergeParams,
205
223
  },
206
- });
224
+ }));
207
225
  };
208
226
  const selectQueryB = (q) => {
209
227
  const mergeParams = q.mergeFrom !== undefined && q.mergeTo !== undefined
@@ -216,7 +234,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
216
234
  return navigateTo('/',
217
235
  // Filtering the _b suffix causes us to reset potential profile
218
236
  // selection when running a new query.
219
- {
237
+ filterEmptyParams({
220
238
  ...filterSuffix(queryParams, '_b'),
221
239
  ...{
222
240
  compare_b: 'true',
@@ -226,11 +244,12 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
226
244
  from_b: q.from.toString(),
227
245
  to_b: q.to.toString(),
228
246
  time_selection_b: q.timeSelection,
247
+ sum_by_b: sumByToParam(q.sumBy),
229
248
  filter_by_function: filter_by_function ?? '',
230
249
  dashboard_items: dashboard_items ?? DEFAULT_DASHBOARD_ITEMS,
231
250
  ...mergeParams,
232
251
  },
233
- });
252
+ }));
234
253
  };
235
254
  const closeProfile = (card) => {
236
255
  let newQueryParameters = queryParams;
@@ -9,7 +9,6 @@ export declare const ProfileMetricsEmptyState: ({ message }: ProfileMetricsEmpty
9
9
  interface ProfileMetricsGraphProps {
10
10
  queryClient: QueryServiceClient;
11
11
  queryExpression: string;
12
- dirtyQueryExpression: string;
13
12
  profile: ProfileSelection | null;
14
13
  from: number;
15
14
  to: number;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAGlD,OAAO,EAAW,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAY,MAAM,eAAe,CAAC;AACjG,OAAO,EACL,aAAa,EAKd,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAK5D,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,eAAO,MAAM,wBAAwB,gBAAe,6BAA6B,KAAG,GAAG,CAAC,OAMvF,CAAC;AAEF,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,oBAAoB,EAAE,MAAM,CAAC;IAC7B,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CACf,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,YAAY,EAAE,CACZ,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,KACb,IAAI,CAAC;IACV,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;CACxB;AAYD,eAAO,MAAM,aAAa,WAChB,kBAAkB,mBACT,MAAM,SAChB,MAAM,OACR,MAAM,SACJ,MAAM,EAAE,qBAEd,gBA+CF,CAAC;AAEF,QAAA,MAAM,mBAAmB,sIAYtB,wBAAwB,KAAG,GAAG,CAAC,OAqFjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAGlD,OAAO,EAAW,KAAK,EAAE,kBAAkB,EAAE,kBAAkB,EAAY,MAAM,eAAe,CAAC;AACjG,OAAO,EACL,aAAa,EAKd,MAAM,mBAAmB,CAAC;AAI3B,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAK5D,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,eAAO,MAAM,wBAAwB,gBAAe,6BAA6B,KAAG,GAAG,CAAC,OAMvF,CAAC;AAEF,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,eAAe,EAAE,MAAM,CAAC;IACxB,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,OAAO,CAAC;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,YAAY,EAAE,CAAC,KAAK,EAAE,aAAa,KAAK,IAAI,CAAC;IAC7C,eAAe,EAAE,CACf,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,YAAY,EAAE,CACZ,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,KAAK,EAAE,EACf,eAAe,EAAE,MAAM,EACvB,QAAQ,EAAE,MAAM,KACb,IAAI,CAAC;IACV,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;CACxB;AAYD,eAAO,MAAM,aAAa,WAChB,kBAAkB,mBACT,MAAM,SAChB,MAAM,OACR,MAAM,SACJ,MAAM,EAAE,qBAEd,gBA+CF,CAAC;AAEF,QAAA,MAAM,mBAAmB,sIAYtB,wBAAwB,KAAG,GAAG,CAAC,OAqFjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -53,7 +53,7 @@ export const useQueryRange = (client, queryExpression, start, end, sumBy, skip =
53
53
  }
54
54
  }, [stepCountStr, defaultStepCount, setStepCount]);
55
55
  const { data, isLoading, error } = useGrpcQuery({
56
- key: ['query-range', queryExpression, start, end, sumBy.join(','), stepCount, metadata],
56
+ key: ['query-range', queryExpression, start, end, (sumBy ?? []).join(','), stepCount, metadata],
57
57
  queryFn: async () => {
58
58
  const stepDuration = getStepDuration(start, end, stepCount);
59
59
  const { response } = await client.queryRange({
@@ -29,6 +29,6 @@ export interface IProfileTypesResult {
29
29
  error?: RpcError;
30
30
  }
31
31
  export declare const useProfileTypes: (client: QueryServiceClient) => IProfileTypesResult;
32
- declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, suffix, }: ProfileSelectorProps) => JSX.Element;
32
+ declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, }: ProfileSelectorProps) => JSX.Element;
33
33
  export default ProfileSelector;
34
34
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAGlD,OAAO,EAAQ,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY9E,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAQ5D,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,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;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,WAAY,kBAAkB,KAAG,mBAkB5D,CAAC;AAEF,QAAA,MAAM,eAAe,qJAWlB,oBAAoB,KAAG,GAAG,CAAC,OAsT7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/index.tsx"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAGlD,OAAO,EAAQ,oBAAoB,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAY9E,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AAQ5D,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,oBAAoB;IAC5B,WAAW,EAAE,kBAAkB,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,SAAS,EAAE,OAAO,CAAC;IACnB,UAAU,EAAE,gBAAgB,CAAC;IAC7B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;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,WAAY,kBAAkB,KAAG,mBAkB5D,CAAC;AAEF,QAAA,MAAM,eAAe,6IAUlB,oBAAoB,KAAG,GAAG,CAAC,OAwT7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -21,7 +21,7 @@ import MatchersInput, { useLabelNames } from '../MatchersInput/index';
21
21
  import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
22
22
  import ProfileMetricsGraph, { ProfileMetricsEmptyState } from '../ProfileMetricsGraph';
23
23
  import ProfileTypeSelector from '../ProfileTypeSelector/index';
24
- import { useSumBy } from '../useSumBy';
24
+ import { useDefaultSumBy, useSumBySelection } from '../useSumBy';
25
25
  import { useAutoQuerySelector } from './useAutoQuerySelector';
26
26
  export const useProfileTypes = (client) => {
27
27
  const [result, setResult] = useState(undefined);
@@ -40,7 +40,7 @@ export const useProfileTypes = (client) => {
40
40
  }, [client, metadata, loading]);
41
41
  return { loading, data: result, error };
42
42
  };
43
- const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, suffix = '', }) => {
43
+ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, }) => {
44
44
  const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient);
45
45
  const { heightStyle } = useMetricsGraphDimensions(comparing);
46
46
  const { viewComponent } = useParcaContext();
@@ -49,19 +49,23 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
49
49
  const profileType = useMemo(() => {
50
50
  return Query.parse(queryExpressionString).profileType();
51
51
  }, [queryExpressionString]);
52
+ const selectedProfileType = useMemo(() => {
53
+ return Query.parse(querySelection.expression).profileType();
54
+ }, [querySelection.expression]);
52
55
  const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType.toString());
56
+ const { loading: selectedLabelNamesLoading, result: selectedLabelNamesResult } = useLabelNames(queryClient, selectedProfileType.toString());
53
57
  const labels = useMemo(() => {
54
58
  return result.response?.labelNames === undefined ? [] : result.response.labelNames;
55
59
  }, [result]);
56
- const [sumBy, setSumBy, userSelectedSumBy] = useSumBy(profileType, labelNamesLoading, result.response?.labelNames, {
57
- urlParamKey: 'sum_by' + suffix,
60
+ const selectedLabels = useMemo(() => {
61
+ return selectedLabelNamesResult.response?.labelNames === undefined
62
+ ? []
63
+ : selectedLabelNamesResult.response.labelNames;
64
+ }, [selectedLabelNamesResult]);
65
+ const [sumBySelection, setUserSumBySelection, { isLoading: sumBySelectionLoading }] = useSumBySelection(profileType, labelNamesLoading, labels, {
66
+ defaultValue: querySelection.sumBy,
58
67
  });
59
- const [sumBySelection, setSumBySelection] = useSumBy(profileType, labelNamesLoading, result.response?.labelNames, {
60
- urlParamKey: 'sum_by_selection' + suffix,
61
- withURLUpdate: false,
62
- defaultValue: userSelectedSumBy,
63
- });
64
- const sumByLoading = labelNamesLoading;
68
+ const { defaultSumBy, isLoading: defaultSumByLoading } = useDefaultSumBy(selectedProfileType, selectedLabelNamesLoading, selectedLabels);
65
69
  useEffect(() => {
66
70
  if (enforcedProfileName !== '') {
67
71
  const [q, changed] = Query.parse(querySelection.expression).setProfileName(enforcedProfileName);
@@ -80,9 +84,6 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
80
84
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
81
85
  const selectedProfileName = query.profileName();
82
86
  const setNewQueryExpression = (expr, updateTs = false) => {
83
- if (!sumByLoading) {
84
- setSumBy(sumBySelection);
85
- }
86
87
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
87
88
  const delta = query.profileType().delta;
88
89
  const from = timeRangeSelection.getFromMs(updateTs);
@@ -98,6 +99,7 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
98
99
  from,
99
100
  to,
100
101
  timeSelection: timeRangeSelection.getRangeKey(),
102
+ sumBy: sumBySelection,
101
103
  ...mergeParams,
102
104
  });
103
105
  };
@@ -157,24 +159,25 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
157
159
  profileTypesData,
158
160
  setProfileName,
159
161
  setQueryExpression,
160
- querySelection: { ...querySelection, sumBy },
162
+ querySelection: { ...querySelection, sumBy: sumBySelection },
161
163
  navigateTo,
164
+ loading: sumBySelectionLoading,
162
165
  });
163
166
  const searchDisabled = queryExpressionString === undefined ||
164
167
  queryExpressionString === '' ||
165
168
  queryExpressionString === '{}';
166
169
  return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "mb-2 flex gap-2", children: [_jsxs("div", { className: "flex w-full flex-wrap content-start items-center gap-2", children: [_jsxs("div", { className: "pb-6", children: [_jsx("label", { className: "text-xs", children: "Profile type" }), _jsx(ProfileTypeSelector, { profileTypesData: profileTypesData, loading: profileTypesLoading, selectedKey: selectedProfileName, onSelection: setProfileName, error: error, disabled: viewComponent?.disableProfileTypesDropdown })] }), _jsxs("div", { className: "w-full flex-1 pb-6", children: [_jsxs("div", { className: "mb-0.5 mt-1.5 flex items-center justify-between", children: [_jsx("label", { className: "text-xs", children: "Query" }), (query.matchers.length > 0 || query.inputMatcherString.length > 0) &&
167
- viewComponent !== undefined && _jsx("div", { children: viewComponent?.createViewComponent })] }), _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName })] }), _jsxs("div", { className: "pb-6", 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, { defaultValue: [], isMulti: true, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-80", classNamePrefix: "parca-select", value: sumBySelection.map(sumBy => ({ label: sumBy, value: sumBy })), onChange: selectedOptions => {
168
- setSumBySelection(selectedOptions.map(option => option.value));
170
+ viewComponent !== undefined && _jsx("div", { children: viewComponent?.createViewComponent })] }), _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName })] }), _jsxs("div", { className: "pb-6", 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, { defaultValue: [], isMulti: true, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container text-sm w-80", classNamePrefix: "parca-select", value: (sumBySelection ?? []).map(sumBy => ({ label: sumBy, value: sumBy })), onChange: selectedOptions => {
171
+ setUserSumBySelection(selectedOptions.map(option => option.value));
169
172
  }, placeholder: "Labels...", styles: {
170
173
  indicatorSeparator: () => ({ display: 'none' }),
171
- } })] }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsx(ButtonGroup, { children: _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
174
+ }, isDisabled: !profileType.delta })] }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsx(ButtonGroup, { children: _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
172
175
  e.preventDefault();
173
176
  setQueryExpression(true);
174
177
  }, id: "h-matcher-search-button", children: "Search" }) })] }), _jsx("div", { children: comparing && _jsx(IconButton, { onClick: () => closeProfile(), icon: _jsx(CloseIcon, {}) }) })] }), _jsx("div", { className: "rounded bg-white shadow dark:border-gray-500 dark:bg-gray-700", children: _jsx("div", { style: { height: heightStyle }, children: querySelection.expression !== undefined &&
175
178
  querySelection.expression.length > 0 &&
176
179
  querySelection.from !== undefined &&
177
- querySelection.to !== undefined ? (_jsx("div", { className: "p-2", children: _jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, dirtyQueryExpression: queryExpressionString, from: querySelection.from, to: querySelection.to, profile: profileSelection, comparing: comparing, sumBy: sumBy, sumByLoading: sumByLoading, setTimeRange: (range) => {
180
+ querySelection.to !== undefined ? (_jsx("div", { className: "p-2", children: _jsx(ProfileMetricsGraph, { queryClient: queryClient, queryExpression: querySelection.expression, from: querySelection.from, to: querySelection.to, profile: profileSelection, comparing: comparing, sumBy: querySelection.sumBy ?? defaultSumBy ?? [], sumByLoading: defaultSumByLoading, setTimeRange: (range) => {
178
181
  const from = range.getFromMs();
179
182
  const to = range.getToMs();
180
183
  let mergedProfileParams = {};
@@ -8,7 +8,8 @@ interface Props {
8
8
  setQueryExpression: () => void;
9
9
  querySelection: QuerySelection;
10
10
  navigateTo: NavigateFunction;
11
+ loading: boolean;
11
12
  }
12
- export declare const useAutoQuerySelector: ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, }: Props) => void;
13
+ export declare const useAutoQuerySelector: ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, loading, }: Props) => void;
13
14
  export {};
14
15
  //# sourceMappingURL=useAutoQuerySelector.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useAutoQuerySelector.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/useAutoQuerySelector.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGlD,UAAU,KAAK;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACnD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,eAAO,MAAM,oBAAoB,+GAO9B,KAAK,KAAG,IAkIV,CAAC"}
1
+ {"version":3,"file":"useAutoQuerySelector.d.ts","sourceRoot":"","sources":["../../src/ProfileSelector/useAutoQuerySelector.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,oBAAoB,EAAC,MAAM,eAAe,CAAC;AAEnD,OAAO,EAAC,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAGvD,OAAO,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAGlD,UAAU,KAAK;IACb,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,oBAAoB,GAAG,SAAS,CAAC;IACnD,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,UAAU,EAAE,gBAAgB,CAAC;IAC7B,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,eAAO,MAAM,oBAAoB,wHAQ9B,KAAK,KAAG,IAuIV,CAAC"}
@@ -14,13 +14,16 @@ import { useEffect } from 'react';
14
14
  import { selectAutoQuery, setAutoQuery, useAppDispatch, useAppSelector } from '@parca/store';
15
15
  import { ProfileSelectionFromParams, SuffixParams } from '..';
16
16
  import { constructProfileName } from '../ProfileTypeSelector';
17
- export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, }) => {
17
+ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, setProfileName, setQueryExpression, querySelection, navigateTo, loading, }) => {
18
18
  const autoQuery = useAppSelector(selectAutoQuery);
19
19
  const dispatch = useAppDispatch();
20
20
  const queryParams = new URLSearchParams(location.search);
21
21
  const comparing = queryParams.get('comparing') === 'true';
22
22
  const expressionA = queryParams.get('expression_a');
23
23
  useEffect(() => {
24
+ if (loading) {
25
+ return;
26
+ }
24
27
  if (comparing && expressionA !== null && expressionA !== undefined) {
25
28
  if (querySelection.expression === undefined) {
26
29
  return;
@@ -62,7 +65,7 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
62
65
  dashboard_items: ['icicle'],
63
66
  });
64
67
  }
65
- }, [comparing, querySelection, navigateTo, expressionA, dispatch]);
68
+ }, [comparing, querySelection, navigateTo, expressionA, dispatch, loading]);
66
69
  // Effect to load some initial data on load when is no selection
67
70
  useEffect(() => {
68
71
  void (async () => {
@@ -105,7 +108,8 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
105
108
  if (autoQuery !== 'true' ||
106
109
  profileTypesData?.types == null ||
107
110
  profileTypesData.types.length < 1 ||
108
- selectedProfileName.length === 0) {
111
+ selectedProfileName.length === 0 ||
112
+ loading) {
109
113
  return;
110
114
  }
111
115
  setQueryExpression();
@@ -118,5 +122,6 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
118
122
  setProfileName,
119
123
  dispatch,
120
124
  selectedProfileName,
125
+ loading,
121
126
  ]);
122
127
  };
@@ -6,8 +6,9 @@ interface Props<IRes> {
6
6
  enabled?: boolean | undefined;
7
7
  staleTime?: number | undefined;
8
8
  retry?: number | boolean;
9
+ keepPreviousData?: boolean | undefined;
9
10
  };
10
11
  }
11
- declare const useGrpcQuery: <IRes>({ key, queryFn, options: { enabled, staleTime, retry }, }: Props<IRes>) => UseQueryResult<IRes>;
12
+ declare const useGrpcQuery: <IRes>({ key, queryFn, options: { enabled, staleTime, retry, keepPreviousData }, }: Props<IRes>) => UseQueryResult<IRes>;
12
13
  export default useGrpcQuery;
13
14
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/useGrpcQuery/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAW,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAEpE,UAAU,KAAK,CAAC,IAAI;IAClB,GAAG,EAAE,OAAO,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;KAC1B,CAAC;CACH;AAED,QAAA,MAAM,YAAY,GAAI,IAAI,6DAIvB,KAAK,CAAC,IAAI,CAAC,KAAG,cAAc,CAAC,IAAI,CAYnC,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/useGrpcQuery/index.ts"],"names":[],"mappings":"AAaA,OAAO,EAAW,KAAK,cAAc,EAAC,MAAM,uBAAuB,CAAC;AAEpE,UAAU,KAAK,CAAC,IAAI;IAClB,GAAG,EAAE,OAAO,EAAE,CAAC;IACf,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,OAAO,CAAC,EAAE;QACR,OAAO,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;QAC9B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;QAC/B,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QACzB,gBAAgB,CAAC,EAAE,OAAO,GAAG,SAAS,CAAC;KACxC,CAAC;CACH;AAED,QAAA,MAAM,YAAY,GAAI,IAAI,+EAIvB,KAAK,CAAC,IAAI,CAAC,KAAG,cAAc,CAAC,IAAI,CAanC,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -11,13 +11,14 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
  import { useQuery } from '@tanstack/react-query';
14
- const useGrpcQuery = ({ key, queryFn, options: { enabled = true, staleTime, retry } = {}, }) => {
14
+ const useGrpcQuery = ({ key, queryFn, options: { enabled = true, staleTime, retry, keepPreviousData } = {}, }) => {
15
15
  return useQuery(key, async () => {
16
16
  return await queryFn();
17
17
  }, {
18
18
  enabled,
19
19
  staleTime,
20
20
  retry,
21
+ keepPreviousData,
21
22
  });
22
23
  };
23
24
  export default useGrpcQuery;
@@ -1,8 +1,14 @@
1
1
  import { ProfileType } from '@parca/parser';
2
2
  export declare const DEFAULT_EMPTY_SUM_BY: string[];
3
- export declare const useSumBy: (profileType: ProfileType | undefined, labelNamesLoading: boolean, labels: string[] | undefined, { urlParamKey, withURLUpdate, defaultValue, }?: {
4
- urlParamKey?: string;
5
- withURLUpdate?: boolean;
3
+ export declare const useSumBySelection: (profileType: ProfileType | undefined, labelNamesLoading: boolean, labels: string[] | undefined, { defaultValue, }?: {
6
4
  defaultValue?: string[];
7
- }) => [string[], (labels: string[]) => void, string[] | undefined];
5
+ }) => [string[] | undefined, (labels: string[]) => void, {
6
+ isLoading: boolean;
7
+ }];
8
+ export declare const useDefaultSumBy: (profileType: ProfileType | undefined, labelNamesLoading: boolean, labels: string[] | undefined) => {
9
+ defaultSumBy: string[] | undefined;
10
+ isLoading: boolean;
11
+ };
12
+ export declare const useSumByFromParams: (param: string | string[] | undefined) => string[] | undefined;
13
+ export declare const sumByToParam: (sumBy: string[] | undefined) => string | string[] | undefined;
8
14
  //# sourceMappingURL=useSumBy.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSumBy.d.ts","sourceRoot":"","sources":["../src/useSumBy.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AAyBjD,eAAO,MAAM,QAAQ,gBACN,WAAW,GAAG,SAAS,qBACjB,OAAO,UAClB,MAAM,EAAE,GAAG,SAAS,kDAKzB;IACD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,KACA,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,EAAE,MAAM,EAAE,GAAG,SAAS,CAkE7D,CAAC"}
1
+ {"version":3,"file":"useSumBy.d.ts","sourceRoot":"","sources":["../src/useSumBy.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AA6BjD,eAAO,MAAM,iBAAiB,gBACf,WAAW,GAAG,SAAS,qBACjB,OAAO,UAClB,MAAM,EAAE,GAAG,SAAS,sBAGzB;IACD,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB,KACA,CACD,MAAM,EAAE,GAAG,SAAS,EACpB,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,EAC1B;IACE,SAAS,EAAE,OAAO,CAAC;CACpB,CAsCF,CAAC;AAEF,eAAO,MAAM,eAAe,gBACb,WAAW,GAAG,SAAS,qBACjB,OAAO,UAClB,MAAM,EAAE,GAAG,SAAS,KAC3B;IAAC,YAAY,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAMzD,CAAC;AAkBF,eAAO,MAAM,kBAAkB,UAAW,MAAM,GAAG,MAAM,EAAE,GAAG,SAAS,KAAG,MAAM,EAAE,GAAG,SAMpF,CAAC;AAEF,eAAO,MAAM,YAAY,UAAW,MAAM,EAAE,GAAG,SAAS,KAAG,MAAM,GAAG,MAAM,EAAE,GAAG,SAU9E,CAAC"}
package/dist/useSumBy.js CHANGED
@@ -10,13 +10,15 @@
10
10
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
- import { useCallback, useEffect, useMemo, useState } from 'react';
14
- import { useParcaContext, useURLState } from '@parca/components';
13
+ import { useCallback, useMemo, useState } from 'react';
15
14
  export const DEFAULT_EMPTY_SUM_BY = [];
16
15
  const getDefaultSumBy = (profile, labels) => {
17
16
  if (profile === undefined || labels === undefined) {
18
17
  return undefined;
19
18
  }
19
+ if (!profile.delta) {
20
+ return DEFAULT_EMPTY_SUM_BY;
21
+ }
20
22
  if (labels.includes('comm')) {
21
23
  return ['comm'];
22
24
  }
@@ -28,51 +30,62 @@ const getDefaultSumBy = (profile, labels) => {
28
30
  }
29
31
  return undefined;
30
32
  };
31
- export const useSumBy = (profileType, labelNamesLoading, labels, { urlParamKey = 'sum_by', withURLUpdate = true, defaultValue, } = {}) => {
32
- const { navigateTo } = useParcaContext();
33
- const [userSelectedSumByParam, setUserSelectedSumByParam] = useURLState({
34
- param: urlParamKey,
35
- navigateTo,
36
- withURLUpdate,
37
- });
38
- const userSelectedSumBy = useMemo(() => {
39
- if (userSelectedSumByParam?.length === 0) {
40
- return undefined;
41
- }
42
- if (userSelectedSumByParam === '__none__') {
43
- return [];
44
- }
45
- if (userSelectedSumByParam === undefined && defaultValue !== undefined) {
46
- return defaultValue;
47
- }
48
- if (typeof userSelectedSumByParam === 'string') {
49
- return [userSelectedSumByParam];
50
- }
51
- return userSelectedSumByParam;
52
- // eslint-disable-next-line react-hooks/exhaustive-deps
53
- }, [userSelectedSumByParam]);
54
- const setUserSelectedSumBy = useCallback((sumBy) => {
55
- if (sumBy.length === 0) {
56
- setUserSelectedSumByParam('__none__');
57
- return;
58
- }
59
- if (sumBy.length === 1) {
60
- // Handle this separately to take care of the empty string scenario
61
- setUserSelectedSumByParam(sumBy[0]);
62
- return;
63
- }
64
- setUserSelectedSumByParam(sumBy);
65
- }, [setUserSelectedSumByParam]);
66
- const [defaultSumBy, setDefaultSumBy] = useState(getDefaultSumBy(profileType, labels));
67
- useEffect(() => {
68
- if (labelNamesLoading) {
69
- return;
70
- }
71
- setDefaultSumBy(getDefaultSumBy(profileType, labels));
72
- }, [profileType, labels, labelNamesLoading]);
73
- let sumBy = userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
33
+ export const useSumBySelection = (profileType, labelNamesLoading, labels, { defaultValue, } = {}) => {
34
+ const [userSelectedSumBy, setUserSelectedSumBy] = useState(profileType != null ? { [profileType.toString()]: defaultValue } : {});
35
+ const setSumBy = useCallback((sumBy) => {
36
+ setUserSelectedSumBy(prev => {
37
+ if (profileType == null) {
38
+ return prev;
39
+ }
40
+ return {
41
+ ...prev,
42
+ [profileType.toString()]: sumBy,
43
+ };
44
+ });
45
+ }, [setUserSelectedSumBy, profileType]);
46
+ const { defaultSumBy } = useDefaultSumBy(profileType, labelNamesLoading, labels);
47
+ let sumBy = userSelectedSumBy[profileType?.toString() ?? ''] ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
74
48
  if (profileType?.delta !== true) {
75
- sumBy = [];
49
+ sumBy = DEFAULT_EMPTY_SUM_BY;
50
+ }
51
+ return [
52
+ labelNamesLoading ? undefined : sumBy,
53
+ setSumBy,
54
+ {
55
+ isLoading: labelNamesLoading,
56
+ },
57
+ ];
58
+ };
59
+ export const useDefaultSumBy = (profileType, labelNamesLoading, labels) => {
60
+ const defaultSumBy = useMemo(() => {
61
+ return getDefaultSumBy(profileType, labels);
62
+ }, [profileType, labels]);
63
+ return { defaultSumBy, isLoading: labelNamesLoading };
64
+ };
65
+ const getSumByFromParam = (param) => {
66
+ if (param?.length === 0) {
67
+ return undefined;
68
+ }
69
+ if (param === '__none__') {
70
+ return [];
71
+ }
72
+ if (typeof param === 'string') {
73
+ return [param];
74
+ }
75
+ return param;
76
+ };
77
+ export const useSumByFromParams = (param) => {
78
+ const sumBy = useMemo(() => {
79
+ return getSumByFromParam(param);
80
+ }, [param]);
81
+ return sumBy;
82
+ };
83
+ export const sumByToParam = (sumBy) => {
84
+ if (sumBy === undefined) {
85
+ return undefined;
86
+ }
87
+ if (sumBy.length === 0) {
88
+ return '__none__';
76
89
  }
77
- return [sumBy, setUserSelectedSumBy, userSelectedSumBy];
90
+ return sumBy;
78
91
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.413",
3
+ "version": "0.16.415",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@headlessui/react": "^1.7.19",
@@ -73,5 +73,5 @@
73
73
  "access": "public",
74
74
  "registry": "https://registry.npmjs.org/"
75
75
  },
76
- "gitHead": "8b3121b9f7c20b041cf55ca866260acbe0bd70c2"
76
+ "gitHead": "4e0b35d45ffe7a449f875b54a8921dc05f2070e7"
77
77
  }
@@ -21,6 +21,7 @@ import {useGrpcMetadata} from '@parca/components';
21
21
  import {Query} from '@parca/parser';
22
22
  import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
23
23
 
24
+ import useGrpcQuery from '../useGrpcQuery';
24
25
  import SuggestionsList, {Suggestion, Suggestions} from './SuggestionsList';
25
26
 
26
27
  interface MatchersInputProps {
@@ -47,33 +48,30 @@ export const useLabelNames = (
47
48
  start?: number,
48
49
  end?: number
49
50
  ): UseLabelNames => {
50
- const [loading, setLoading] = useState(true);
51
- const [result, setResult] = useState<ILabelNamesResult>({});
52
51
  const metadata = useGrpcMetadata();
53
52
 
54
- useEffect(() => {
55
- if (profileType === undefined || profileType === '') {
56
- return;
57
- }
58
-
59
- const request: LabelsRequest = {match: []};
60
- if (start !== undefined && end !== undefined) {
61
- request.start = millisToProtoTimestamp(start);
62
- request.end = millisToProtoTimestamp(end);
63
- }
64
- if (profileType !== undefined) {
65
- request.profileType = profileType;
66
- }
67
- const call = client.labels(request, {meta: metadata});
68
- setLoading(true);
69
-
70
- call.response
71
- .then(response => setResult({response}))
72
- .catch(error => setResult({error}))
73
- .finally(() => setLoading(false));
74
- }, [client, metadata, start, end, profileType]);
75
-
76
- return {result, loading};
53
+ const {data, isLoading, error} = useGrpcQuery<LabelsResponse>({
54
+ key: ['labelNames', profileType],
55
+ queryFn: async () => {
56
+ const request: LabelsRequest = {match: []};
57
+ if (start !== undefined && end !== undefined) {
58
+ request.start = millisToProtoTimestamp(start);
59
+ request.end = millisToProtoTimestamp(end);
60
+ }
61
+ if (profileType !== undefined) {
62
+ request.profileType = profileType;
63
+ }
64
+ const {response} = await client.labels(request, {meta: metadata});
65
+ return response;
66
+ },
67
+ options: {
68
+ enabled: profileType !== undefined && profileType !== '',
69
+ staleTime: 1000 * 60 * 5, // 5 minutes
70
+ keepPreviousData: false,
71
+ },
72
+ });
73
+
74
+ return {result: {response: data, error: error as Error}, loading: isLoading};
77
75
  };
78
76
 
79
77
  const MatchersInput = ({
@@ -22,6 +22,7 @@ import {capitalizeOnlyFirstLetter, type NavigateFunction} from '@parca/utilities
22
22
 
23
23
  import {ProfileSelection, ProfileSelectionFromParams, SuffixParams} from '..';
24
24
  import {QuerySelection, useProfileTypes} from '../ProfileSelector';
25
+ import {sumByToParam, useSumByFromParams} from '../useSumBy';
25
26
  import ProfileExplorerCompare from './ProfileExplorerCompare';
26
27
  import ProfileExplorerSingle from './ProfileExplorerSingle';
27
28
 
@@ -64,6 +65,25 @@ const sanitizeDateRange = (
64
65
  };
65
66
  /* eslint-enable @typescript-eslint/naming-convention */
66
67
 
68
+ const filterEmptyParams = (o: Record<string, any>): Record<string, any> => {
69
+ return Object.fromEntries(
70
+ Object.entries(o)
71
+ .filter(
72
+ ([_, value]) =>
73
+ value !== '' && value !== undefined && (Array.isArray(value) ? value.length > 0 : true)
74
+ )
75
+ .map(([key, value]) => {
76
+ if (typeof value === 'string') {
77
+ return [key, value];
78
+ }
79
+ if (Array.isArray(value)) {
80
+ return [key, value];
81
+ }
82
+ return [key, value];
83
+ })
84
+ );
85
+ };
86
+
67
87
  const filterSuffix = (
68
88
  o: {[key: string]: string | string[] | undefined},
69
89
  suffix: string
@@ -148,6 +168,9 @@ const ProfileExplorerApp = ({
148
168
  const [profileA, setProfileA] = useState<ProfileSelection | null>(null);
149
169
  const [profileB, setProfileB] = useState<ProfileSelection | null>(null);
150
170
 
171
+ const sumByA = useSumByFromParams(sum_by_a);
172
+ const sumByB = useSumByFromParams(sum_by_b);
173
+
151
174
  useEffect(() => {
152
175
  const mergeFrom = merge_from_a ?? undefined;
153
176
  const mergeTo = merge_to_a ?? undefined;
@@ -225,7 +248,7 @@ const ProfileExplorerApp = ({
225
248
  from: parseInt(from_a as string),
226
249
  to: parseInt(to_a as string),
227
250
  timeSelection: time_selection_a as string,
228
- sumBy: sum_by_a as string[],
251
+ sumBy: sumByA,
229
252
  };
230
253
 
231
254
  // Show the SingleProfileExplorer when not comparing
@@ -243,17 +266,18 @@ const ProfileExplorerApp = ({
243
266
  '/',
244
267
  // Filtering the _a suffix causes us to reset potential profile
245
268
  // selection when running a new query.
246
- {
269
+ filterEmptyParams({
247
270
  ...filterSuffix(queryParams, '_a'),
248
271
  ...{
249
272
  expression_a: encodeURIComponent(q.expression),
250
273
  from_a: q.from.toString(),
251
274
  to_a: q.to.toString(),
252
275
  time_selection_a: q.timeSelection,
276
+ sum_by_a: sumByToParam(q.sumBy),
253
277
  dashboard_items: dashboard_items ?? DEFAULT_DASHBOARD_ITEMS,
254
278
  ...mergeParams,
255
279
  },
256
- }
280
+ })
257
281
  );
258
282
  };
259
283
 
@@ -283,7 +307,7 @@ const ProfileExplorerApp = ({
283
307
  from: parseInt(from_b as string),
284
308
  to: parseInt(to_b as string),
285
309
  timeSelection: time_selection_b as string,
286
- sumBy: sum_by_b as string[],
310
+ sumBy: sumByB,
287
311
  };
288
312
 
289
313
  const selectQueryA = (q: QuerySelection): void => {
@@ -299,7 +323,7 @@ const ProfileExplorerApp = ({
299
323
  '/',
300
324
  // Filtering the _a suffix causes us to reset potential profile
301
325
  // selection when running a new query.
302
- {
326
+ filterEmptyParams({
303
327
  ...filterSuffix(queryParams, '_a'),
304
328
  ...{
305
329
  compare_a: 'true',
@@ -309,11 +333,12 @@ const ProfileExplorerApp = ({
309
333
  from_a: q.from.toString(),
310
334
  to_a: q.to.toString(),
311
335
  time_selection_a: q.timeSelection,
336
+ sum_by_a: sumByToParam(q.sumBy),
312
337
  filter_by_function: filter_by_function ?? '',
313
338
  dashboard_items: dashboard_items ?? DEFAULT_DASHBOARD_ITEMS,
314
339
  ...mergeParams,
315
340
  },
316
- }
341
+ })
317
342
  );
318
343
  };
319
344
 
@@ -330,7 +355,7 @@ const ProfileExplorerApp = ({
330
355
  '/',
331
356
  // Filtering the _b suffix causes us to reset potential profile
332
357
  // selection when running a new query.
333
- {
358
+ filterEmptyParams({
334
359
  ...filterSuffix(queryParams, '_b'),
335
360
  ...{
336
361
  compare_b: 'true',
@@ -340,11 +365,12 @@ const ProfileExplorerApp = ({
340
365
  from_b: q.from.toString(),
341
366
  to_b: q.to.toString(),
342
367
  time_selection_b: q.timeSelection,
368
+ sum_by_b: sumByToParam(q.sumBy),
343
369
  filter_by_function: filter_by_function ?? '',
344
370
  dashboard_items: dashboard_items ?? DEFAULT_DASHBOARD_ITEMS,
345
371
  ...mergeParams,
346
372
  },
347
- }
373
+ })
348
374
  );
349
375
  };
350
376
 
@@ -58,7 +58,6 @@ export const ProfileMetricsEmptyState = ({message}: ProfileMetricsEmptyStateProp
58
58
  interface ProfileMetricsGraphProps {
59
59
  queryClient: QueryServiceClient;
60
60
  queryExpression: string;
61
- dirtyQueryExpression: string;
62
61
  profile: ProfileSelection | null;
63
62
  from: number;
64
63
  to: number;
@@ -123,7 +122,7 @@ export const useQueryRange = (
123
122
  }, [stepCountStr, defaultStepCount, setStepCount]);
124
123
 
125
124
  const {data, isLoading, error} = useGrpcQuery<QueryRangeResponse | undefined>({
126
- key: ['query-range', queryExpression, start, end, sumBy.join(','), stepCount, metadata],
125
+ key: ['query-range', queryExpression, start, end, (sumBy ?? []).join(','), stepCount, metadata],
127
126
  queryFn: async () => {
128
127
  const stepDuration = getStepDuration(start, end, stepCount);
129
128
  const {response} = await client.queryRange(
@@ -35,7 +35,7 @@ import MatchersInput, {useLabelNames} from '../MatchersInput/index';
35
35
  import {useMetricsGraphDimensions} from '../MetricsGraph/useMetricsGraphDimensions';
36
36
  import ProfileMetricsGraph, {ProfileMetricsEmptyState} from '../ProfileMetricsGraph';
37
37
  import ProfileTypeSelector from '../ProfileTypeSelector/index';
38
- import {useSumBy} from '../useSumBy';
38
+ import {useDefaultSumBy, useSumBySelection} from '../useSumBy';
39
39
  import {useAutoQuerySelector} from './useAutoQuerySelector';
40
40
 
41
41
  export interface QuerySelection {
@@ -97,7 +97,6 @@ const ProfileSelector = ({
97
97
  profileSelection,
98
98
  comparing,
99
99
  navigateTo,
100
- suffix = '',
101
100
  }: ProfileSelectorProps): JSX.Element => {
102
101
  const {
103
102
  loading: profileTypesLoading,
@@ -117,33 +116,36 @@ const ProfileSelector = ({
117
116
  return Query.parse(queryExpressionString).profileType();
118
117
  }, [queryExpressionString]);
119
118
 
119
+ const selectedProfileType = useMemo(() => {
120
+ return Query.parse(querySelection.expression).profileType();
121
+ }, [querySelection.expression]);
122
+
120
123
  const {loading: labelNamesLoading, result} = useLabelNames(queryClient, profileType.toString());
124
+ const {loading: selectedLabelNamesLoading, result: selectedLabelNamesResult} = useLabelNames(
125
+ queryClient,
126
+ selectedProfileType.toString()
127
+ );
121
128
 
122
129
  const labels = useMemo(() => {
123
130
  return result.response?.labelNames === undefined ? [] : result.response.labelNames;
124
131
  }, [result]);
125
132
 
126
- const [sumBy, setSumBy, userSelectedSumBy] = useSumBy(
127
- profileType,
128
- labelNamesLoading,
129
- result.response?.labelNames,
130
- {
131
- urlParamKey: 'sum_by' + suffix,
132
- }
133
- );
133
+ const selectedLabels = useMemo(() => {
134
+ return selectedLabelNamesResult.response?.labelNames === undefined
135
+ ? []
136
+ : selectedLabelNamesResult.response.labelNames;
137
+ }, [selectedLabelNamesResult]);
134
138
 
135
- const [sumBySelection, setSumBySelection] = useSumBy(
136
- profileType,
137
- labelNamesLoading,
138
- result.response?.labelNames,
139
- {
140
- urlParamKey: 'sum_by_selection' + suffix,
141
- withURLUpdate: false,
142
- defaultValue: userSelectedSumBy,
143
- }
144
- );
139
+ const [sumBySelection, setUserSumBySelection, {isLoading: sumBySelectionLoading}] =
140
+ useSumBySelection(profileType, labelNamesLoading, labels, {
141
+ defaultValue: querySelection.sumBy,
142
+ });
145
143
 
146
- const sumByLoading = labelNamesLoading;
144
+ const {defaultSumBy, isLoading: defaultSumByLoading} = useDefaultSumBy(
145
+ selectedProfileType,
146
+ selectedLabelNamesLoading,
147
+ selectedLabels
148
+ );
147
149
 
148
150
  useEffect(() => {
149
151
  if (enforcedProfileName !== '') {
@@ -169,9 +171,6 @@ const ProfileSelector = ({
169
171
  const selectedProfileName = query.profileName();
170
172
 
171
173
  const setNewQueryExpression = (expr: string, updateTs = false): void => {
172
- if (!sumByLoading) {
173
- setSumBy(sumBySelection);
174
- }
175
174
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
176
175
  const delta = query.profileType().delta;
177
176
  const from = timeRangeSelection.getFromMs(updateTs);
@@ -188,6 +187,7 @@ const ProfileSelector = ({
188
187
  from,
189
188
  to,
190
189
  timeSelection: timeRangeSelection.getRangeKey(),
190
+ sumBy: sumBySelection,
191
191
  ...mergeParams,
192
192
  });
193
193
  };
@@ -257,8 +257,9 @@ const ProfileSelector = ({
257
257
  profileTypesData,
258
258
  setProfileName,
259
259
  setQueryExpression,
260
- querySelection: {...querySelection, sumBy},
260
+ querySelection: {...querySelection, sumBy: sumBySelection},
261
261
  navigateTo,
262
+ loading: sumBySelectionLoading,
262
263
  });
263
264
 
264
265
  const searchDisabled =
@@ -306,14 +307,15 @@ const ProfileSelector = ({
306
307
  options={labels.map(label => ({label, value: label}))}
307
308
  className="parca-select-container text-sm w-80"
308
309
  classNamePrefix="parca-select"
309
- value={sumBySelection.map(sumBy => ({label: sumBy, value: sumBy}))}
310
+ value={(sumBySelection ?? []).map(sumBy => ({label: sumBy, value: sumBy}))}
310
311
  onChange={selectedOptions => {
311
- setSumBySelection(selectedOptions.map(option => option.value));
312
+ setUserSumBySelection(selectedOptions.map(option => option.value));
312
313
  }}
313
314
  placeholder="Labels..."
314
315
  styles={{
315
316
  indicatorSeparator: () => ({display: 'none'}),
316
317
  }}
318
+ isDisabled={!profileType.delta}
317
319
  />
318
320
  </div>
319
321
  <DateTimeRangePicker
@@ -345,13 +347,12 @@ const ProfileSelector = ({
345
347
  <ProfileMetricsGraph
346
348
  queryClient={queryClient}
347
349
  queryExpression={querySelection.expression}
348
- dirtyQueryExpression={queryExpressionString}
349
350
  from={querySelection.from}
350
351
  to={querySelection.to}
351
352
  profile={profileSelection}
352
353
  comparing={comparing}
353
- sumBy={sumBy}
354
- sumByLoading={sumByLoading}
354
+ sumBy={querySelection.sumBy ?? defaultSumBy ?? []}
355
+ sumByLoading={defaultSumByLoading}
355
356
  setTimeRange={(range: DateTimeRange) => {
356
357
  const from = range.getFromMs();
357
358
  const to = range.getToMs();
@@ -28,6 +28,7 @@ interface Props {
28
28
  setQueryExpression: () => void;
29
29
  querySelection: QuerySelection;
30
30
  navigateTo: NavigateFunction;
31
+ loading: boolean;
31
32
  }
32
33
 
33
34
  export const useAutoQuerySelector = ({
@@ -37,6 +38,7 @@ export const useAutoQuerySelector = ({
37
38
  setQueryExpression,
38
39
  querySelection,
39
40
  navigateTo,
41
+ loading,
40
42
  }: Props): void => {
41
43
  const autoQuery = useAppSelector(selectAutoQuery);
42
44
  const dispatch = useAppDispatch();
@@ -46,6 +48,9 @@ export const useAutoQuerySelector = ({
46
48
  const expressionA = queryParams.get('expression_a');
47
49
 
48
50
  useEffect(() => {
51
+ if (loading) {
52
+ return;
53
+ }
49
54
  if (comparing && expressionA !== null && expressionA !== undefined) {
50
55
  if (querySelection.expression === undefined) {
51
56
  return;
@@ -98,7 +103,7 @@ export const useAutoQuerySelector = ({
98
103
  dashboard_items: ['icicle'],
99
104
  });
100
105
  }
101
- }, [comparing, querySelection, navigateTo, expressionA, dispatch]);
106
+ }, [comparing, querySelection, navigateTo, expressionA, dispatch, loading]);
102
107
 
103
108
  // Effect to load some initial data on load when is no selection
104
109
  useEffect(() => {
@@ -152,7 +157,8 @@ export const useAutoQuerySelector = ({
152
157
  autoQuery !== 'true' ||
153
158
  profileTypesData?.types == null ||
154
159
  profileTypesData.types.length < 1 ||
155
- selectedProfileName.length === 0
160
+ selectedProfileName.length === 0 ||
161
+ loading
156
162
  ) {
157
163
  return;
158
164
  }
@@ -166,5 +172,6 @@ export const useAutoQuerySelector = ({
166
172
  setProfileName,
167
173
  dispatch,
168
174
  selectedProfileName,
175
+ loading,
169
176
  ]);
170
177
  };
@@ -20,13 +20,14 @@ interface Props<IRes> {
20
20
  enabled?: boolean | undefined;
21
21
  staleTime?: number | undefined;
22
22
  retry?: number | boolean;
23
+ keepPreviousData?: boolean | undefined;
23
24
  };
24
25
  }
25
26
 
26
27
  const useGrpcQuery = <IRes>({
27
28
  key,
28
29
  queryFn,
29
- options: {enabled = true, staleTime, retry} = {},
30
+ options: {enabled = true, staleTime, retry, keepPreviousData} = {},
30
31
  }: Props<IRes>): UseQueryResult<IRes> => {
31
32
  return useQuery<IRes>(
32
33
  key,
@@ -37,6 +38,7 @@ const useGrpcQuery = <IRes>({
37
38
  enabled,
38
39
  staleTime,
39
40
  retry,
41
+ keepPreviousData,
40
42
  }
41
43
  );
42
44
  };
package/src/useSumBy.ts CHANGED
@@ -11,9 +11,8 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import {useCallback, useEffect, useMemo, useState} from 'react';
14
+ import {useCallback, useMemo, useState} from 'react';
15
15
 
16
- import {useParcaContext, useURLState} from '@parca/components';
17
16
  import {ProfileType} from '@parca/parser';
18
17
 
19
18
  export const DEFAULT_EMPTY_SUM_BY: string[] = [];
@@ -26,6 +25,10 @@ const getDefaultSumBy = (
26
25
  return undefined;
27
26
  }
28
27
 
28
+ if (!profile.delta) {
29
+ return DEFAULT_EMPTY_SUM_BY;
30
+ }
31
+
29
32
  if (labels.includes('comm')) {
30
33
  return ['comm'];
31
34
  }
@@ -41,83 +44,104 @@ const getDefaultSumBy = (
41
44
  return undefined;
42
45
  };
43
46
 
44
- export const useSumBy = (
47
+ export const useSumBySelection = (
45
48
  profileType: ProfileType | undefined,
46
49
  labelNamesLoading: boolean,
47
50
  labels: string[] | undefined,
48
51
  {
49
- urlParamKey = 'sum_by',
50
- withURLUpdate = true,
51
52
  defaultValue,
52
53
  }: {
53
- urlParamKey?: string;
54
- withURLUpdate?: boolean;
55
54
  defaultValue?: string[];
56
55
  } = {}
57
- ): [string[], (labels: string[]) => void, string[] | undefined] => {
58
- const {navigateTo} = useParcaContext();
59
- const [userSelectedSumByParam, setUserSelectedSumByParam] = useURLState({
60
- param: urlParamKey,
61
- navigateTo,
62
- withURLUpdate,
63
- });
56
+ ): [
57
+ string[] | undefined,
58
+ (labels: string[]) => void,
59
+ {
60
+ isLoading: boolean;
61
+ }
62
+ ] => {
63
+ const [userSelectedSumBy, setUserSelectedSumBy] = useState<Record<string, string[] | undefined>>(
64
+ profileType != null ? {[profileType.toString()]: defaultValue} : {}
65
+ );
64
66
 
65
- const userSelectedSumBy = useMemo<string[] | undefined>(() => {
66
- if (userSelectedSumByParam?.length === 0) {
67
- return undefined;
68
- }
67
+ const setSumBy = useCallback(
68
+ (sumBy: string[]) => {
69
+ setUserSelectedSumBy(prev => {
70
+ if (profileType == null) {
71
+ return prev;
72
+ }
73
+
74
+ return {
75
+ ...prev,
76
+ [profileType.toString()]: sumBy,
77
+ };
78
+ });
79
+ },
80
+ [setUserSelectedSumBy, profileType]
81
+ );
69
82
 
70
- if (userSelectedSumByParam === '__none__') {
71
- return [];
72
- }
83
+ const {defaultSumBy} = useDefaultSumBy(profileType, labelNamesLoading, labels);
73
84
 
74
- if (userSelectedSumByParam === undefined && defaultValue !== undefined) {
75
- return defaultValue;
76
- }
85
+ let sumBy =
86
+ userSelectedSumBy[profileType?.toString() ?? ''] ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
77
87
 
78
- if (typeof userSelectedSumByParam === 'string') {
79
- return [userSelectedSumByParam];
80
- }
88
+ if (profileType?.delta !== true) {
89
+ sumBy = DEFAULT_EMPTY_SUM_BY;
90
+ }
81
91
 
82
- return userSelectedSumByParam;
92
+ return [
93
+ labelNamesLoading ? undefined : sumBy,
94
+ setSumBy,
95
+ {
96
+ isLoading: labelNamesLoading,
97
+ },
98
+ ];
99
+ };
83
100
 
84
- // eslint-disable-next-line react-hooks/exhaustive-deps
85
- }, [userSelectedSumByParam]);
101
+ export const useDefaultSumBy = (
102
+ profileType: ProfileType | undefined,
103
+ labelNamesLoading: boolean,
104
+ labels: string[] | undefined
105
+ ): {defaultSumBy: string[] | undefined; isLoading: boolean} => {
106
+ const defaultSumBy = useMemo(() => {
107
+ return getDefaultSumBy(profileType, labels);
108
+ }, [profileType, labels]);
86
109
 
87
- const setUserSelectedSumBy = useCallback(
88
- (sumBy: string[]) => {
89
- if (sumBy.length === 0) {
90
- setUserSelectedSumByParam('__none__');
91
- return;
92
- }
93
-
94
- if (sumBy.length === 1) {
95
- // Handle this separately to take care of the empty string scenario
96
- setUserSelectedSumByParam(sumBy[0]);
97
- return;
98
- }
99
-
100
- setUserSelectedSumByParam(sumBy);
101
- },
102
- [setUserSelectedSumByParam]
103
- );
110
+ return {defaultSumBy, isLoading: labelNamesLoading};
111
+ };
104
112
 
105
- const [defaultSumBy, setDefaultSumBy] = useState<string[] | undefined>(
106
- getDefaultSumBy(profileType, labels)
107
- );
113
+ const getSumByFromParam = (param: string | string[] | undefined): string[] | undefined => {
114
+ if (param?.length === 0) {
115
+ return undefined;
116
+ }
108
117
 
109
- useEffect(() => {
110
- if (labelNamesLoading) {
111
- return;
112
- }
113
- setDefaultSumBy(getDefaultSumBy(profileType, labels));
114
- }, [profileType, labels, labelNamesLoading]);
118
+ if (param === '__none__') {
119
+ return [];
120
+ }
115
121
 
116
- let sumBy = userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
122
+ if (typeof param === 'string') {
123
+ return [param];
124
+ }
117
125
 
118
- if (profileType?.delta !== true) {
119
- sumBy = [];
126
+ return param;
127
+ };
128
+
129
+ export const useSumByFromParams = (param: string | string[] | undefined): string[] | undefined => {
130
+ const sumBy = useMemo(() => {
131
+ return getSumByFromParam(param);
132
+ }, [param]);
133
+
134
+ return sumBy;
135
+ };
136
+
137
+ export const sumByToParam = (sumBy: string[] | undefined): string | string[] | undefined => {
138
+ if (sumBy === undefined) {
139
+ return undefined;
140
+ }
141
+
142
+ if (sumBy.length === 0) {
143
+ return '__none__';
120
144
  }
121
145
 
122
- return [sumBy, setUserSelectedSumBy, userSelectedSumBy];
146
+ return sumBy;
123
147
  };