@parca/profile 0.19.95 → 0.19.103
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 +32 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +65 -45
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +16 -4
- package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.d.ts +11 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.d.ts.map +1 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.js +65 -0
- package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.js +35 -5
- package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.js +29 -3
- package/dist/ProfileSelector/MetricsGraphSection.d.ts +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +1 -1
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +1 -2
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +8 -0
- package/dist/SimpleMatchers/Select.d.ts.map +1 -1
- package/dist/SimpleMatchers/Select.js +3 -3
- package/dist/hooks/useLabels.d.ts.map +1 -1
- package/dist/hooks/useLabels.js +7 -2
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +53 -23
- package/dist/hooks/useQueryState.test.js +32 -22
- package/dist/styles.css +1 -1
- package/dist/useSumBy.d.ts +10 -2
- package/dist/useSumBy.d.ts.map +1 -1
- package/dist/useSumBy.js +30 -7
- package/package.json +15 -10
- package/src/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.tsx +89 -57
- package/src/ProfileFlameGraph/FlameGraphArrow/index.tsx +27 -2
- package/src/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.ts +84 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.ts +40 -5
- package/src/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.ts +41 -5
- package/src/ProfileSelector/MetricsGraphSection.tsx +2 -2
- package/src/ProfileSelector/index.tsx +1 -5
- package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +8 -0
- package/src/SimpleMatchers/Select.tsx +3 -3
- package/src/hooks/useLabels.ts +8 -2
- package/src/hooks/useQueryState.test.tsx +41 -22
- package/src/hooks/useQueryState.ts +72 -31
- package/src/useSumBy.ts +58 -4
package/src/hooks/useLabels.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
+
import {useEffect} from 'react';
|
|
15
|
+
|
|
14
16
|
import {LabelsRequest, LabelsResponse, QueryServiceClient, ValuesRequest} from '@parca/client';
|
|
15
17
|
import {useGrpcMetadata} from '@parca/components';
|
|
16
18
|
import {millisToProtoTimestamp, sanitizeLabelValue} from '@parca/utilities';
|
|
@@ -68,7 +70,9 @@ export const useLabelNames = (
|
|
|
68
70
|
},
|
|
69
71
|
});
|
|
70
72
|
|
|
71
|
-
|
|
73
|
+
useEffect(() => {
|
|
74
|
+
console.log('Label names query result:', {data, error, isLoading});
|
|
75
|
+
}, [data, error, isLoading]);
|
|
72
76
|
|
|
73
77
|
return {
|
|
74
78
|
result: {response: data, error: error as Error},
|
|
@@ -109,7 +113,9 @@ export const useLabelValues = (
|
|
|
109
113
|
},
|
|
110
114
|
});
|
|
111
115
|
|
|
112
|
-
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
console.log('Label values query result:', {data, error, isLoading, labelName});
|
|
118
|
+
}, [data, error, isLoading, labelName]);
|
|
113
119
|
|
|
114
120
|
return {
|
|
115
121
|
result: {response: data ?? [], error: error as Error},
|
|
@@ -69,16 +69,33 @@ vi.mock('@parca/components/src/hooks/URLState/utils', async () => {
|
|
|
69
69
|
};
|
|
70
70
|
});
|
|
71
71
|
|
|
72
|
-
// Mock useSumBy
|
|
72
|
+
// Mock useSumBy with stateful behavior using React's useState
|
|
73
73
|
vi.mock('../useSumBy', async () => {
|
|
74
74
|
const actual = await vi.importActual('../useSumBy');
|
|
75
|
+
const react = await import('react');
|
|
76
|
+
|
|
75
77
|
return {
|
|
76
78
|
...actual,
|
|
77
|
-
useSumBy: (
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
useSumBy: (
|
|
80
|
+
_queryClient: any,
|
|
81
|
+
_profileType: any,
|
|
82
|
+
_timeRange: any,
|
|
83
|
+
_draftProfileType: any,
|
|
84
|
+
_draftTimeRange: any,
|
|
85
|
+
defaultValue: any
|
|
86
|
+
) => {
|
|
87
|
+
const [draftSumBy, setDraftSumBy] = react.useState<string[] | undefined>(defaultValue);
|
|
88
|
+
const [sumBy, setSumBy] = react.useState<string[] | undefined>(defaultValue);
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
sumBy,
|
|
92
|
+
setSumBy,
|
|
93
|
+
isLoading: false,
|
|
94
|
+
draftSumBy,
|
|
95
|
+
setDraftSumBy,
|
|
96
|
+
isDraftSumByLoading: false,
|
|
97
|
+
};
|
|
98
|
+
},
|
|
82
99
|
};
|
|
83
100
|
});
|
|
84
101
|
|
|
@@ -207,7 +224,9 @@ describe('useQueryState', () => {
|
|
|
207
224
|
it('should update sumBy', async () => {
|
|
208
225
|
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
209
226
|
|
|
227
|
+
// sumBy only applies to delta profiles, so we need to set one first
|
|
210
228
|
act(() => {
|
|
229
|
+
result.current.setDraftExpression('process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}');
|
|
211
230
|
result.current.setDraftSumBy(['namespace', 'container']);
|
|
212
231
|
});
|
|
213
232
|
|
|
@@ -256,15 +275,15 @@ describe('useQueryState', () => {
|
|
|
256
275
|
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
257
276
|
|
|
258
277
|
act(() => {
|
|
259
|
-
// Update multiple draft values
|
|
260
|
-
result.current.setDraftExpression('memory:
|
|
278
|
+
// Update multiple draft values (using delta profile since sumBy only applies to delta)
|
|
279
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
261
280
|
result.current.setDraftTimeRange(7000, 8000, 'relative:minute|30');
|
|
262
281
|
result.current.setDraftSumBy(['pod', 'node']);
|
|
263
282
|
});
|
|
264
283
|
|
|
265
284
|
// All drafts should be updated
|
|
266
285
|
expect(result.current.draftSelection.expression).toBe(
|
|
267
|
-
'memory:
|
|
286
|
+
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
268
287
|
);
|
|
269
288
|
expect(result.current.draftSelection.from).toBe(7000);
|
|
270
289
|
expect(result.current.draftSelection.to).toBe(8000);
|
|
@@ -278,7 +297,7 @@ describe('useQueryState', () => {
|
|
|
278
297
|
// Should only navigate once for all updates
|
|
279
298
|
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
280
299
|
const [, params] = mockNavigateTo.mock.calls[0];
|
|
281
|
-
expect(params.expression).toBe('memory:
|
|
300
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
282
301
|
expect(params.from).toBe('7000');
|
|
283
302
|
expect(params.to).toBe('8000');
|
|
284
303
|
expect(params.time_selection).toBe('relative:minute|30');
|
|
@@ -430,9 +449,9 @@ describe('useQueryState', () => {
|
|
|
430
449
|
it('should handle _b suffix correctly', async () => {
|
|
431
450
|
const {result} = renderHook(() => useQueryState({suffix: '_b'}), {wrapper: createWrapper()});
|
|
432
451
|
|
|
433
|
-
// Update draft state
|
|
452
|
+
// Update draft state (using delta profile since sumBy only applies to delta)
|
|
434
453
|
act(() => {
|
|
435
|
-
result.current.setDraftExpression('memory:
|
|
454
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
436
455
|
result.current.setDraftTimeRange(3333, 4444, 'relative:hour|2');
|
|
437
456
|
result.current.setDraftSumBy(['label_b']);
|
|
438
457
|
});
|
|
@@ -445,7 +464,7 @@ describe('useQueryState', () => {
|
|
|
445
464
|
await waitFor(() => {
|
|
446
465
|
expect(mockNavigateTo).toHaveBeenCalled();
|
|
447
466
|
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
448
|
-
expect(params.expression_b).toBe('memory:
|
|
467
|
+
expect(params.expression_b).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
449
468
|
expect(params.from_b).toBe('3333');
|
|
450
469
|
expect(params.to_b).toBe('4444');
|
|
451
470
|
expect(params.sum_by_b).toBe('label_b');
|
|
@@ -457,9 +476,9 @@ describe('useQueryState', () => {
|
|
|
457
476
|
it('should not update URL until commit', async () => {
|
|
458
477
|
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
459
478
|
|
|
460
|
-
// Make multiple draft changes
|
|
479
|
+
// Make multiple draft changes (using delta profile since sumBy only applies to delta)
|
|
461
480
|
act(() => {
|
|
462
|
-
result.current.setDraftExpression('memory:
|
|
481
|
+
result.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
463
482
|
result.current.setDraftTimeRange(5000, 6000, 'relative:hour|3');
|
|
464
483
|
result.current.setDraftSumBy(['namespace', 'pod']);
|
|
465
484
|
});
|
|
@@ -476,7 +495,7 @@ describe('useQueryState', () => {
|
|
|
476
495
|
await waitFor(() => {
|
|
477
496
|
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
478
497
|
const [, params] = mockNavigateTo.mock.calls[0];
|
|
479
|
-
expect(params.expression).toBe('memory:
|
|
498
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
480
499
|
expect(params.from).toBe('5000');
|
|
481
500
|
expect(params.to).toBe('6000');
|
|
482
501
|
expect(params.sum_by).toBe('namespace,pod');
|
|
@@ -737,17 +756,17 @@ describe('useQueryState', () => {
|
|
|
737
756
|
|
|
738
757
|
describe('State persistence after page reload', () => {
|
|
739
758
|
it('should retain committed values after page reload simulation', async () => {
|
|
740
|
-
// Initial state
|
|
759
|
+
// Initial state (using delta profile since sumBy only applies to delta)
|
|
741
760
|
mockLocation.search =
|
|
742
|
-
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&from=1000&to=2000';
|
|
761
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000';
|
|
743
762
|
|
|
744
763
|
const {result: result1, unmount} = renderHook(() => useQueryState(), {
|
|
745
764
|
wrapper: createWrapper(),
|
|
746
765
|
});
|
|
747
766
|
|
|
748
|
-
// User makes changes to draft
|
|
767
|
+
// User makes changes to draft (using delta profile since sumBy only applies to delta)
|
|
749
768
|
act(() => {
|
|
750
|
-
result1.current.setDraftExpression('memory:
|
|
769
|
+
result1.current.setDraftExpression('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
751
770
|
result1.current.setDraftTimeRange(5000, 6000, 'relative:minute|15');
|
|
752
771
|
result1.current.setDraftSumBy(['namespace', 'pod']);
|
|
753
772
|
});
|
|
@@ -786,7 +805,7 @@ describe('useQueryState', () => {
|
|
|
786
805
|
|
|
787
806
|
// Verify state is loaded from URL after "reload"
|
|
788
807
|
expect(result2.current.querySelection.expression).toBe(
|
|
789
|
-
'memory:
|
|
808
|
+
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
790
809
|
);
|
|
791
810
|
expect(result2.current.querySelection.from).toBe(5000);
|
|
792
811
|
expect(result2.current.querySelection.to).toBe(6000);
|
|
@@ -795,7 +814,7 @@ describe('useQueryState', () => {
|
|
|
795
814
|
|
|
796
815
|
// Draft should be synced with URL state on page load
|
|
797
816
|
expect(result2.current.draftSelection.expression).toBe(
|
|
798
|
-
'memory:
|
|
817
|
+
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
799
818
|
);
|
|
800
819
|
expect(result2.current.draftSelection.from).toBe(5000);
|
|
801
820
|
expect(result2.current.draftSelection.to).toBe(6000);
|
|
@@ -19,7 +19,8 @@ import {Query} from '@parca/parser';
|
|
|
19
19
|
import {QuerySelection} from '../ProfileSelector';
|
|
20
20
|
import {ProfileSelection, ProfileSelectionFromParams, ProfileSource} from '../ProfileSource';
|
|
21
21
|
import {useResetFlameGraphState} from '../ProfileView/hooks/useResetFlameGraphState';
|
|
22
|
-
import {
|
|
22
|
+
import {useResetStateOnProfileTypeChange} from '../ProfileView/hooks/useResetStateOnProfileTypeChange';
|
|
23
|
+
import {DEFAULT_EMPTY_SUM_BY, sumByToParam, useSumBy, useSumByFromParams} from '../useSumBy';
|
|
23
24
|
|
|
24
25
|
interface UseQueryStateOptions {
|
|
25
26
|
suffix?: '_a' | '_b'; // For comparison mode
|
|
@@ -79,6 +80,7 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
79
80
|
|
|
80
81
|
const batchUpdates = useURLStateBatch();
|
|
81
82
|
const resetFlameGraphState = useResetFlameGraphState();
|
|
83
|
+
const resetStateOnProfileTypeChange = useResetStateOnProfileTypeChange();
|
|
82
84
|
|
|
83
85
|
// URL state hooks with appropriate suffixes
|
|
84
86
|
const [expression, setExpressionState] = useURLState<string>(`expression${suffix}`, {
|
|
@@ -115,29 +117,6 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
115
117
|
const [draftTimeSelection, setDraftTimeSelection] = useState<string>(
|
|
116
118
|
timeSelection ?? defaultTimeSelection
|
|
117
119
|
);
|
|
118
|
-
const [draftSumBy, setDraftSumBy] = useState<string[] | undefined>(sumBy);
|
|
119
|
-
|
|
120
|
-
// Sync draft state with URL state when URL changes externally
|
|
121
|
-
useEffect(() => {
|
|
122
|
-
setDraftExpression(expression ?? defaultExpression);
|
|
123
|
-
}, [expression, defaultExpression]);
|
|
124
|
-
|
|
125
|
-
useEffect(() => {
|
|
126
|
-
setDraftFrom(from ?? defaultFrom?.toString() ?? '');
|
|
127
|
-
}, [from, defaultFrom]);
|
|
128
|
-
|
|
129
|
-
useEffect(() => {
|
|
130
|
-
setDraftTo(to ?? defaultTo?.toString() ?? '');
|
|
131
|
-
}, [to, defaultTo]);
|
|
132
|
-
|
|
133
|
-
useEffect(() => {
|
|
134
|
-
setDraftTimeSelection(timeSelection ?? defaultTimeSelection);
|
|
135
|
-
}, [timeSelection, defaultTimeSelection]);
|
|
136
|
-
|
|
137
|
-
useEffect(() => {
|
|
138
|
-
setDraftSumBy(sumBy);
|
|
139
|
-
}, [sumBy]);
|
|
140
|
-
|
|
141
120
|
// Parse the draft query to extract profile information
|
|
142
121
|
const draftQuery = useMemo(() => {
|
|
143
122
|
try {
|
|
@@ -147,8 +126,16 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
147
126
|
}
|
|
148
127
|
}, [draftExpression]);
|
|
149
128
|
|
|
129
|
+
const query = useMemo(() => {
|
|
130
|
+
try {
|
|
131
|
+
return Query.parse(expression ?? '');
|
|
132
|
+
} catch {
|
|
133
|
+
return Query.parse('');
|
|
134
|
+
}
|
|
135
|
+
}, [expression]);
|
|
150
136
|
const draftProfileType = useMemo(() => draftQuery.profileType(), [draftQuery]);
|
|
151
137
|
const draftProfileName = useMemo(() => draftQuery.profileName(), [draftQuery]);
|
|
138
|
+
const profileType = useMemo(() => query.profileType(), [query]);
|
|
152
139
|
|
|
153
140
|
// Compute draft time range for label fetching
|
|
154
141
|
const draftTimeRange = useMemo(() => {
|
|
@@ -159,13 +146,50 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
159
146
|
);
|
|
160
147
|
}, [draftTimeSelection, draftFrom, draftTo, defaultTimeSelection, defaultFrom, defaultTo]);
|
|
161
148
|
// Use combined sumBy hook for fetching labels and computing defaults (based on committed state)
|
|
162
|
-
const {
|
|
149
|
+
const {
|
|
150
|
+
sumBy: computedSumByFromURL,
|
|
151
|
+
isLoading: sumBySelectionLoading,
|
|
152
|
+
draftSumBy,
|
|
153
|
+
setDraftSumBy,
|
|
154
|
+
isDraftSumByLoading,
|
|
155
|
+
} = useSumBy(
|
|
163
156
|
queryClient,
|
|
157
|
+
profileType?.profileName !== '' ? profileType : draftProfileType,
|
|
158
|
+
draftTimeRange,
|
|
164
159
|
draftProfileType,
|
|
165
160
|
draftTimeRange,
|
|
166
161
|
sumBy
|
|
167
162
|
);
|
|
168
163
|
|
|
164
|
+
// Sync draft state with URL state when URL changes externally
|
|
165
|
+
useEffect(() => {
|
|
166
|
+
setDraftExpression(expression ?? defaultExpression);
|
|
167
|
+
}, [expression, defaultExpression]);
|
|
168
|
+
|
|
169
|
+
useEffect(() => {
|
|
170
|
+
setDraftFrom(from ?? defaultFrom?.toString() ?? '');
|
|
171
|
+
}, [from, defaultFrom]);
|
|
172
|
+
|
|
173
|
+
useEffect(() => {
|
|
174
|
+
setDraftTo(to ?? defaultTo?.toString() ?? '');
|
|
175
|
+
}, [to, defaultTo]);
|
|
176
|
+
|
|
177
|
+
useEffect(() => {
|
|
178
|
+
setDraftTimeSelection(timeSelection ?? defaultTimeSelection);
|
|
179
|
+
}, [timeSelection, defaultTimeSelection]);
|
|
180
|
+
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
setDraftSumBy(sumBy);
|
|
183
|
+
}, [sumBy, setDraftSumBy]);
|
|
184
|
+
|
|
185
|
+
// Sync computed sumBy to URL if URL doesn't already have a value
|
|
186
|
+
// to ensure the shared URL can always pick it up.
|
|
187
|
+
useEffect(() => {
|
|
188
|
+
if (sumByParam === undefined && computedSumByFromURL !== undefined && !sumBySelectionLoading) {
|
|
189
|
+
setSumByParam(sumByToParam(computedSumByFromURL));
|
|
190
|
+
}
|
|
191
|
+
}, [sumByParam, computedSumByFromURL, sumBySelectionLoading, setSumByParam]);
|
|
192
|
+
|
|
169
193
|
// Construct the QuerySelection object (committed state from URL)
|
|
170
194
|
const querySelection: QuerySelection = useMemo(() => {
|
|
171
195
|
const range = DateTimeRange.fromRangeKey(
|
|
@@ -285,12 +309,16 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
285
309
|
setFromState(finalFrom);
|
|
286
310
|
setToState(finalTo);
|
|
287
311
|
setTimeSelectionState(finalTimeSelection);
|
|
288
|
-
setSumByParam(sumByToParam(draftSumBy));
|
|
289
312
|
|
|
290
313
|
// Auto-calculate merge parameters for delta profiles
|
|
291
314
|
// Parse the final expression to check if it's a delta profile
|
|
292
315
|
const finalQuery = Query.parse(finalExpression);
|
|
293
316
|
const isDelta = finalQuery.profileType().delta;
|
|
317
|
+
if (isDelta) {
|
|
318
|
+
setSumByParam(sumByToParam(draftSumBy));
|
|
319
|
+
} else {
|
|
320
|
+
setSumByParam(DEFAULT_EMPTY_SUM_BY);
|
|
321
|
+
}
|
|
294
322
|
|
|
295
323
|
if (isDelta && finalFrom !== '' && finalTo !== '') {
|
|
296
324
|
const fromMs = parseInt(finalFrom);
|
|
@@ -313,6 +341,12 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
313
341
|
setSelectionParam(undefined);
|
|
314
342
|
}
|
|
315
343
|
resetFlameGraphState();
|
|
344
|
+
if (
|
|
345
|
+
draftProfileType.toString() !==
|
|
346
|
+
Query.parse(querySelection.expression).profileType().toString()
|
|
347
|
+
) {
|
|
348
|
+
resetStateOnProfileTypeChange();
|
|
349
|
+
}
|
|
316
350
|
});
|
|
317
351
|
},
|
|
318
352
|
[
|
|
@@ -334,6 +368,9 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
334
368
|
setMergeToState,
|
|
335
369
|
setSelectionParam,
|
|
336
370
|
resetFlameGraphState,
|
|
371
|
+
resetStateOnProfileTypeChange,
|
|
372
|
+
draftProfileType,
|
|
373
|
+
querySelection.expression,
|
|
337
374
|
]
|
|
338
375
|
);
|
|
339
376
|
|
|
@@ -346,9 +383,12 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
346
383
|
[]
|
|
347
384
|
);
|
|
348
385
|
|
|
349
|
-
const setDraftSumByCallback = useCallback(
|
|
350
|
-
|
|
351
|
-
|
|
386
|
+
const setDraftSumByCallback = useCallback(
|
|
387
|
+
(newSumBy: string[] | undefined) => {
|
|
388
|
+
setDraftSumBy(newSumBy);
|
|
389
|
+
},
|
|
390
|
+
[setDraftSumBy]
|
|
391
|
+
);
|
|
352
392
|
|
|
353
393
|
const setDraftProfileName = useCallback(
|
|
354
394
|
(newProfileName: string) => {
|
|
@@ -357,9 +397,10 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
357
397
|
const [newQuery, changed] = draftQuery.setProfileName(newProfileName);
|
|
358
398
|
if (changed) {
|
|
359
399
|
setDraftExpression(newQuery.toString());
|
|
400
|
+
setDraftSumBy(undefined);
|
|
360
401
|
}
|
|
361
402
|
},
|
|
362
|
-
[draftQuery]
|
|
403
|
+
[draftQuery, setDraftSumBy]
|
|
363
404
|
);
|
|
364
405
|
|
|
365
406
|
const setDraftMatchers = useCallback(
|
|
@@ -421,7 +462,7 @@ export const useQueryState = (options: UseQueryStateOptions = {}): UseQueryState
|
|
|
421
462
|
setProfileSelection,
|
|
422
463
|
|
|
423
464
|
// Loading state
|
|
424
|
-
sumByLoading: sumBySelectionLoading,
|
|
465
|
+
sumByLoading: isDraftSumByLoading || sumBySelectionLoading,
|
|
425
466
|
|
|
426
467
|
draftParsedQuery,
|
|
427
468
|
parsedQuery,
|
package/src/useSumBy.ts
CHANGED
|
@@ -52,6 +52,7 @@ export const useSumBySelection = (
|
|
|
52
52
|
profileType: ProfileType | undefined,
|
|
53
53
|
labelNamesLoading: boolean,
|
|
54
54
|
labels: string[] | undefined,
|
|
55
|
+
draftSumBy: string[] | undefined,
|
|
55
56
|
{
|
|
56
57
|
defaultValue,
|
|
57
58
|
}: {
|
|
@@ -100,9 +101,15 @@ export const useSumBySelection = (
|
|
|
100
101
|
const lastValidSumByRef = useRef<string[]>(DEFAULT_EMPTY_SUM_BY);
|
|
101
102
|
|
|
102
103
|
const sumBy = useMemo(() => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
104
|
+
if (labelNamesLoading) {
|
|
105
|
+
// For smoother UX, return draftSumBy first if available during loading
|
|
106
|
+
// as this must be recently computed with the draft time range labels.
|
|
107
|
+
if (draftSumBy !== undefined) {
|
|
108
|
+
return draftSumBy;
|
|
109
|
+
}
|
|
110
|
+
if (lastValidSumByRef.current == null) {
|
|
111
|
+
return lastValidSumByRef.current;
|
|
112
|
+
}
|
|
106
113
|
}
|
|
107
114
|
|
|
108
115
|
let result =
|
|
@@ -116,7 +123,7 @@ export const useSumBySelection = (
|
|
|
116
123
|
lastValidSumByRef.current = result;
|
|
117
124
|
|
|
118
125
|
return result;
|
|
119
|
-
}, [userSelectedSumBy, profileType, defaultSumBy, labelNamesLoading]);
|
|
126
|
+
}, [userSelectedSumBy, profileType, defaultSumBy, labelNamesLoading, draftSumBy]);
|
|
120
127
|
|
|
121
128
|
return [
|
|
122
129
|
sumBy,
|
|
@@ -187,11 +194,16 @@ export const useSumBy = (
|
|
|
187
194
|
queryClient: QueryServiceClient,
|
|
188
195
|
profileType: ProfileType | undefined,
|
|
189
196
|
timeRange: DateTimeRange,
|
|
197
|
+
draftProfileType: ProfileType | undefined,
|
|
198
|
+
draftTimeRange: DateTimeRange,
|
|
190
199
|
defaultValue?: string[]
|
|
191
200
|
): {
|
|
192
201
|
sumBy: string[] | undefined;
|
|
193
202
|
setSumBy: (sumBy: string[]) => void;
|
|
194
203
|
isLoading: boolean;
|
|
204
|
+
draftSumBy: string[] | undefined;
|
|
205
|
+
setDraftSumBy: (sumBy: string[] | undefined) => void;
|
|
206
|
+
isDraftSumByLoading: boolean;
|
|
195
207
|
} => {
|
|
196
208
|
const {loading: labelNamesLoading, result} = useLabelNames(
|
|
197
209
|
queryClient,
|
|
@@ -200,6 +212,13 @@ export const useSumBy = (
|
|
|
200
212
|
timeRange.getToMs()
|
|
201
213
|
);
|
|
202
214
|
|
|
215
|
+
const {draftSumBy, setDraftSumBy, isDraftSumByLoading} = useDraftSumBy(
|
|
216
|
+
queryClient,
|
|
217
|
+
draftProfileType,
|
|
218
|
+
draftTimeRange,
|
|
219
|
+
defaultValue
|
|
220
|
+
);
|
|
221
|
+
|
|
203
222
|
const labels = useMemo(() => {
|
|
204
223
|
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
205
224
|
}, [result]);
|
|
@@ -208,6 +227,7 @@ export const useSumBy = (
|
|
|
208
227
|
profileType,
|
|
209
228
|
labelNamesLoading,
|
|
210
229
|
labels,
|
|
230
|
+
draftSumBy,
|
|
211
231
|
{defaultValue}
|
|
212
232
|
);
|
|
213
233
|
|
|
@@ -215,5 +235,39 @@ export const useSumBy = (
|
|
|
215
235
|
sumBy: sumBySelection,
|
|
216
236
|
setSumBy: setSumByInternal,
|
|
217
237
|
isLoading,
|
|
238
|
+
draftSumBy,
|
|
239
|
+
setDraftSumBy,
|
|
240
|
+
isDraftSumByLoading,
|
|
241
|
+
};
|
|
242
|
+
};
|
|
243
|
+
|
|
244
|
+
export const useDraftSumBy = (
|
|
245
|
+
queryClient: QueryServiceClient,
|
|
246
|
+
profileType: ProfileType | undefined,
|
|
247
|
+
timeRange: DateTimeRange,
|
|
248
|
+
defaultValue?: string[]
|
|
249
|
+
): {
|
|
250
|
+
draftSumBy: string[] | undefined;
|
|
251
|
+
setDraftSumBy: (sumBy: string[] | undefined) => void;
|
|
252
|
+
isDraftSumByLoading: boolean;
|
|
253
|
+
} => {
|
|
254
|
+
const [draftSumBy, setDraftSumBy] = useState<string[] | undefined>(defaultValue);
|
|
255
|
+
const {loading: labelNamesLoading, result} = useLabelNames(
|
|
256
|
+
queryClient,
|
|
257
|
+
profileType?.toString() ?? '',
|
|
258
|
+
timeRange.getFromMs(),
|
|
259
|
+
timeRange.getToMs()
|
|
260
|
+
);
|
|
261
|
+
|
|
262
|
+
const labels = useMemo(() => {
|
|
263
|
+
return result.response?.labelNames === undefined ? [] : result.response.labelNames;
|
|
264
|
+
}, [result]);
|
|
265
|
+
|
|
266
|
+
const {defaultSumBy, isLoading} = useDefaultSumBy(profileType, labelNamesLoading, labels);
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
draftSumBy: draftSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY,
|
|
270
|
+
setDraftSumBy: setDraftSumBy,
|
|
271
|
+
isDraftSumByLoading: isLoading,
|
|
218
272
|
};
|
|
219
273
|
};
|