@parca/profile 0.19.113 → 0.19.115

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.
Files changed (86) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts.map +1 -1
  3. package/dist/ProfileExplorer/ProfileExplorerSingle.js +9 -3
  4. package/dist/ProfileFlameChart/SamplesStrips/SamplesGraph/index.d.ts +31 -0
  5. package/dist/ProfileFlameChart/SamplesStrips/SamplesGraph/index.d.ts.map +1 -0
  6. package/dist/{MetricsGraphStrips/AreaGraph → ProfileFlameChart/SamplesStrips/SamplesGraph}/index.js +32 -60
  7. package/dist/{MetricsGraphStrips/MetricsGraphStrips.stories.d.ts → ProfileFlameChart/SamplesStrips/SamplesStrips.stories.d.ts} +4 -3
  8. package/dist/ProfileFlameChart/SamplesStrips/SamplesStrips.stories.d.ts.map +1 -0
  9. package/dist/{MetricsGraphStrips/MetricsGraphStrips.stories.js → ProfileFlameChart/SamplesStrips/SamplesStrips.stories.js} +5 -4
  10. package/dist/{MetricsGraphStrips → ProfileFlameChart/SamplesStrips}/index.d.ts +5 -4
  11. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts.map +1 -0
  12. package/dist/ProfileFlameChart/SamplesStrips/index.js +145 -0
  13. package/dist/ProfileFlameChart/index.d.ts +20 -0
  14. package/dist/ProfileFlameChart/index.d.ts.map +1 -0
  15. package/dist/ProfileFlameChart/index.js +155 -0
  16. package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
  17. package/dist/ProfileFlameGraph/index.js +0 -1
  18. package/dist/ProfileMetricsGraph/hooks/useQueryRange.d.ts +2 -1
  19. package/dist/ProfileMetricsGraph/hooks/useQueryRange.d.ts.map +1 -1
  20. package/dist/ProfileMetricsGraph/hooks/useQueryRange.js +11 -21
  21. package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
  22. package/dist/ProfileMetricsGraph/index.js +13 -3
  23. package/dist/ProfileSelector/index.d.ts.map +1 -1
  24. package/dist/ProfileSelector/index.js +4 -0
  25. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.d.ts +1 -0
  26. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.d.ts.map +1 -1
  27. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.js +2 -2
  28. package/dist/ProfileView/components/DashboardItems/index.d.ts +5 -4
  29. package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -1
  30. package/dist/ProfileView/components/DashboardItems/index.js +4 -3
  31. package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts +2 -1
  32. package/dist/ProfileView/components/GroupByLabelsDropdown/index.d.ts.map +1 -1
  33. package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +2 -2
  34. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +1 -1
  35. package/dist/ProfileView/components/Toolbars/index.d.ts +2 -0
  36. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  37. package/dist/ProfileView/components/Toolbars/index.js +4 -2
  38. package/dist/ProfileView/hooks/useAutoSelectDimension.d.ts +16 -0
  39. package/dist/ProfileView/hooks/useAutoSelectDimension.d.ts.map +1 -0
  40. package/dist/ProfileView/hooks/useAutoSelectDimension.js +75 -0
  41. package/dist/ProfileView/hooks/useVisualizationState.d.ts +2 -0
  42. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  43. package/dist/ProfileView/hooks/useVisualizationState.js +8 -0
  44. package/dist/ProfileView/index.d.ts +1 -1
  45. package/dist/ProfileView/index.d.ts.map +1 -1
  46. package/dist/ProfileView/index.js +7 -4
  47. package/dist/ProfileView/types/visualization.d.ts +15 -3
  48. package/dist/ProfileView/types/visualization.d.ts.map +1 -1
  49. package/dist/ProfileViewWithData.d.ts +2 -1
  50. package/dist/ProfileViewWithData.d.ts.map +1 -1
  51. package/dist/ProfileViewWithData.js +41 -29
  52. package/dist/index.d.ts +1 -0
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +4 -0
  55. package/dist/styles.css +1 -1
  56. package/package.json +8 -7
  57. package/src/ProfileExplorer/ProfileExplorerSingle.tsx +14 -3
  58. package/src/{MetricsGraphStrips/AreaGraph → ProfileFlameChart/SamplesStrips/SamplesGraph}/index.tsx +77 -81
  59. package/src/{MetricsGraphStrips/MetricsGraphStrips.stories.tsx → ProfileFlameChart/SamplesStrips/SamplesStrips.stories.tsx} +7 -6
  60. package/src/ProfileFlameChart/SamplesStrips/index.tsx +317 -0
  61. package/src/ProfileFlameChart/index.tsx +305 -0
  62. package/src/ProfileFlameGraph/index.tsx +0 -1
  63. package/src/ProfileMetricsGraph/hooks/useQueryRange.ts +18 -26
  64. package/src/ProfileMetricsGraph/index.tsx +24 -2
  65. package/src/ProfileSelector/index.tsx +11 -0
  66. package/src/ProfileView/components/ActionButtons/GroupByDropdown.tsx +3 -0
  67. package/src/ProfileView/components/DashboardItems/index.tsx +19 -17
  68. package/src/ProfileView/components/GroupByLabelsDropdown/index.tsx +4 -2
  69. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +1 -1
  70. package/src/ProfileView/components/Toolbars/index.tsx +18 -1
  71. package/src/ProfileView/hooks/useAutoSelectDimension.ts +90 -0
  72. package/src/ProfileView/hooks/useVisualizationState.ts +17 -0
  73. package/src/ProfileView/index.tsx +16 -2
  74. package/src/ProfileView/types/visualization.ts +17 -3
  75. package/src/ProfileViewWithData.tsx +80 -37
  76. package/src/index.tsx +4 -0
  77. package/dist/MetricsGraphStrips/AreaGraph/Tooltip.d.ts +0 -10
  78. package/dist/MetricsGraphStrips/AreaGraph/Tooltip.d.ts.map +0 -1
  79. package/dist/MetricsGraphStrips/AreaGraph/Tooltip.js +0 -44
  80. package/dist/MetricsGraphStrips/AreaGraph/index.d.ts +0 -21
  81. package/dist/MetricsGraphStrips/AreaGraph/index.d.ts.map +0 -1
  82. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.d.ts.map +0 -1
  83. package/dist/MetricsGraphStrips/index.d.ts.map +0 -1
  84. package/dist/MetricsGraphStrips/index.js +0 -70
  85. package/src/MetricsGraphStrips/AreaGraph/Tooltip.tsx +0 -83
  86. package/src/MetricsGraphStrips/index.tsx +0 -142
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAOpE,OAAO,EAAC,gBAAgB,EAA0B,MAAM,yBAAyB,CAAC;AAIlF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,uBAAuB,GAClC,eAAe,mBAAmB,KACjC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAMpE,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAqC,qQAoBzD,sBAAsB,KAAG,GAAG,CAAC,OA0T/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileFlameGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwE,MAAM,OAAO,CAAC;AAM7F,OAAO,EAAC,eAAe,EAAC,MAAM,eAAe,CAAC;AAO9C,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAI1C,OAAO,EAAC,mBAAmB,EAAE,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAOpE,OAAO,EAAC,gBAAgB,EAA0B,MAAM,yBAAyB,CAAC;AAIlF,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,sBAAsB;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,gBAAgB,EAAE,GAAG,EAAE,CAAC;IACtC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;IAChC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAUD,eAAO,MAAM,uBAAuB,GAClC,eAAe,mBAAmB,KACjC;IAAC,OAAO,EAAE,OAAO,CAAC;IAAC,UAAU,EAAE,OAAO,CAAC;IAAC,iBAAiB,EAAE,OAAO,CAAA;CAKpE,CAAC;AAEF,QAAA,MAAM,iBAAiB,GAAqC,qQAoBzD,sBAAsB,KAAG,GAAG,CAAC,OA0T/B,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
@@ -32,7 +32,6 @@ const ErrorContent = ({ errorMessage }) => {
32
32
  export const validateFlameChartQuery = (profileSource) => {
33
33
  const isNonDelta = !profileSource.ProfileType().delta;
34
34
  const duration = profileSource.mergeTo - profileSource.mergeFrom;
35
- console.log('duration of flame chart query: ', duration, 'ns');
36
35
  const isDurationTooLong = duration > 60000000000n; // 60 seconds in nanoseconds
37
36
  return { isValid: !isNonDelta && !isDurationTooLong, isNonDelta, isDurationTooLong };
38
37
  };
@@ -4,8 +4,9 @@ interface IQueryRangeState {
4
4
  response: QueryRangeResponse | null;
5
5
  isLoading: boolean;
6
6
  error: RpcError | null;
7
+ stepDurationMs: number;
7
8
  }
8
9
  export declare const getStepCountFromScreenWidth: (pixelsPerPoint: number) => number;
9
- export declare const useQueryRange: (client: QueryServiceClient, queryExpression: string, start: number, end: number, sumBy: string[], skip?: boolean) => IQueryRangeState;
10
+ export declare const useQueryRange: (client: QueryServiceClient, queryExpression: string, start: number, end: number, sumBy: string[], stepCount: number, skip?: boolean) => IQueryRangeState;
10
11
  export {};
11
12
  //# sourceMappingURL=useQueryRange.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useQueryRange.d.ts","sourceRoot":"","sources":["../../../src/ProfileMetricsGraph/hooks/useQueryRange.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAW,kBAAkB,EAAE,kBAAkB,EAAY,MAAM,eAAe,CAAC;AAM1F,UAAU,gBAAgB;IACxB,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;CACxB;AAED,eAAO,MAAM,2BAA2B,GAAI,gBAAgB,MAAM,KAAG,MAQpE,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,QAAQ,kBAAkB,EAC1B,iBAAiB,MAAM,EACvB,OAAO,MAAM,EACb,KAAK,MAAM,EACX,OAAO,MAAM,EAAE,EACf,cAAY,KACX,gBA+CF,CAAC"}
1
+ {"version":3,"file":"useQueryRange.d.ts","sourceRoot":"","sources":["../../../src/ProfileMetricsGraph/hooks/useQueryRange.ts"],"names":[],"mappings":"AAaA,OAAO,EAAC,QAAQ,EAAC,MAAM,0BAA0B,CAAC;AAElD,OAAO,EAAW,kBAAkB,EAAE,kBAAkB,EAAY,MAAM,eAAe,CAAC;AAW1F,UAAU,gBAAgB;IACxB,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,SAAS,EAAE,OAAO,CAAC;IACnB,KAAK,EAAE,QAAQ,GAAG,IAAI,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;CACxB;AAED,eAAO,MAAM,2BAA2B,GAAI,gBAAgB,MAAM,KAAG,MAQpE,CAAC;AAEF,eAAO,MAAM,aAAa,GACxB,QAAQ,kBAAkB,EAC1B,iBAAiB,MAAM,EACvB,OAAO,MAAM,EACb,KAAK,MAAM,EACX,OAAO,MAAM,EAAE,EACf,WAAW,MAAM,EACjB,cAAY,KACX,gBAkCF,CAAC"}
@@ -10,10 +10,9 @@
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 { useEffect, useMemo } from 'react';
14
13
  import { Duration, Timestamp } from '@parca/client';
15
- import { useGrpcMetadata, useURLState } from '@parca/components';
16
- import { getStepDuration } from '@parca/utilities';
14
+ import { useGrpcMetadata } from '@parca/components';
15
+ import { getStepDuration, getStepDurationInMilliseconds } from '@parca/utilities';
17
16
  import useGrpcQuery from '../../useGrpcQuery';
18
17
  export const getStepCountFromScreenWidth = (pixelsPerPoint) => {
19
18
  let width =
@@ -23,27 +22,13 @@ export const getStepCountFromScreenWidth = (pixelsPerPoint) => {
23
22
  width = width - (20 + 24 + 68) * 2;
24
23
  return Math.round(width / pixelsPerPoint);
25
24
  };
26
- export const useQueryRange = (client, queryExpression, start, end, sumBy, skip = false) => {
25
+ export const useQueryRange = (client, queryExpression, start, end, sumBy, stepCount, skip = false) => {
27
26
  const metadata = useGrpcMetadata();
28
- const [stepCountStr, setStepCount] = useURLState('step_count');
29
- const defaultStepCount = useMemo(() => {
30
- return getStepCountFromScreenWidth(10);
31
- }, []);
32
- const stepCount = useMemo(() => {
33
- if (stepCountStr != null) {
34
- return parseInt(stepCountStr, 10);
35
- }
36
- return defaultStepCount;
37
- }, [stepCountStr, defaultStepCount]);
38
- useEffect(() => {
39
- if (stepCountStr == null) {
40
- setStepCount(defaultStepCount.toString());
41
- }
42
- }, [stepCountStr, defaultStepCount, setStepCount]);
43
27
  const { data, isLoading, error } = useGrpcQuery({
44
28
  key: ['query-range', queryExpression, start, end, (sumBy ?? []).join(','), stepCount, metadata],
45
29
  queryFn: async (signal) => {
46
30
  const stepDuration = getStepDuration(start, end, stepCount);
31
+ const stepDurationMs = getStepDurationInMilliseconds(stepDuration);
47
32
  const { response } = await client.queryRange({
48
33
  query: queryExpression,
49
34
  start: Timestamp.fromDate(new Date(start)),
@@ -52,7 +37,7 @@ export const useQueryRange = (client, queryExpression, start, end, sumBy, skip =
52
37
  limit: 0,
53
38
  sumBy,
54
39
  }, { meta: metadata, abort: signal });
55
- return response;
40
+ return { response, stepDurationMs };
56
41
  },
57
42
  options: {
58
43
  retry: false,
@@ -60,5 +45,10 @@ export const useQueryRange = (client, queryExpression, start, end, sumBy, skip =
60
45
  staleTime: 1000 * 60 * 5, // 5 minutes
61
46
  },
62
47
  });
63
- return { isLoading, error: error, response: data ?? null };
48
+ return {
49
+ isLoading,
50
+ error: error,
51
+ response: data?.response ?? null,
52
+ stepDurationMs: data?.stepDurationMs ?? 0,
53
+ };
64
54
  };
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EACL,KAAK,EAGL,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EAId,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AA6G5D,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,eAAO,MAAM,wBAAwB,GAAI,aAAW,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,QAAA,MAAM,mBAAmB,GAAI,qHAW1B,wBAAwB,KAAG,GAAG,CAAC,OA0VjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/index.tsx"],"names":[],"mappings":"AAkBA,OAAO,EACL,KAAK,EAGL,kBAAkB,EACnB,MAAM,eAAe,CAAC;AACvB,OAAO,EACL,aAAa,EAOd,MAAM,mBAAmB,CAAC;AAK3B,OAAO,EAAyB,gBAAgB,EAAC,MAAM,IAAI,CAAC;AA6G5D,UAAU,6BAA6B;IACrC,OAAO,EAAE,MAAM,CAAC;CACjB;AAaD,eAAO,MAAM,wBAAwB,GAAI,aAAW,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,QAAA,MAAM,mBAAmB,GAAI,qHAW1B,wBAAwB,KAAG,GAAG,CAAC,OA6WjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -14,14 +14,14 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
14
14
  import { useEffect, useMemo, useState } from 'react';
15
15
  import { Icon } from '@iconify/react';
16
16
  import { AnimatePresence, motion } from 'framer-motion';
17
- import { MetricsGraphSkeleton, TextWithTooltip, useParcaContext, } from '@parca/components';
17
+ import { MetricsGraphSkeleton, NumberParser, NumberSerializer, TextWithTooltip, useParcaContext, useURLStateCustom, } from '@parca/components';
18
18
  import { Query } from '@parca/parser';
19
19
  import { TEST_IDS, testId } from '@parca/test-utils';
20
20
  import { capitalizeOnlyFirstLetter, formatDate, timePattern, valueFormatter } from '@parca/utilities';
21
21
  import { MergedProfileSelection } from '..';
22
22
  import MetricsGraph from '../MetricsGraph';
23
23
  import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
24
- import { useQueryRange } from './hooks/useQueryRange';
24
+ import { getStepCountFromScreenWidth, useQueryRange } from './hooks/useQueryRange';
25
25
  const createProfileContextMenuItems = (addLabelMatcher, data // The original MetricsSeriesPb[] data
26
26
  ) => {
27
27
  return [
@@ -113,7 +113,17 @@ export const ProfileMetricsEmptyState = ({ message }) => {
113
113
  return (_jsx("div", { className: "flex h-full w-full flex-col items-center justify-center", children: _jsx("p", { children: message }) }));
114
114
  };
115
115
  const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing = false, sumBy, }) => {
116
- const { isLoading: metricsGraphLoading, response, error, } = useQueryRange(queryClient, queryExpression, from, to, sumBy, queryExpression === '');
116
+ const [rawStepCount] = useURLStateCustom('step_count', {
117
+ defaultValue: String(getStepCountFromScreenWidth(10)),
118
+ parse: NumberParser,
119
+ stringify: NumberSerializer,
120
+ });
121
+ // Clamp step count so the step duration is at least 1 second as we don't have this enforced server-side anymore.
122
+ const stepCount = useMemo(() => {
123
+ const maxForOneSecond = Math.floor((to - from) / 1000);
124
+ return Math.min(rawStepCount, maxForOneSecond);
125
+ }, [rawStepCount, from, to]);
126
+ const { isLoading: metricsGraphLoading, response, error, } = useQueryRange(queryClient, queryExpression, from, to, sumBy, stepCount, queryExpression === '');
117
127
  const { onError, perf, authenticationErrorMessage, isDarkMode, timezone } = useParcaContext();
118
128
  const { width, height, margin, heightStyle } = useMetricsGraphDimensions(comparing);
119
129
  const [showAllSeriesForResponse, setShowAllSeriesForResponse] = useState(null);
@@ -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;AAY5F,OAAO,EAAyB,KAAK,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAgB/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,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;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,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,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,OA8O7B,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;AAgB/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,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;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,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,kMAYtB,oBAAoB,KAAG,GAAG,CAAC,OAyP7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -63,6 +63,10 @@ const ProfileSelector = ({ queryClient, closeProfile, enforcedProfileName, compa
63
63
  const { querySelection, draftSelection, setDraftExpression, setDraftTimeRange, setDraftSumBy, setDraftProfileName, setDraftMatchers, commitDraft, profileSelection, setProfileSelection, sumByLoading, draftParsedQuery, } = useQueryState({ suffix, onProfileTypeChange: handleProfileTypeChange });
64
64
  // Use draft state for local state instead of committed state
65
65
  const [timeRangeSelection, setTimeRangeSelection] = useState(DateTimeRange.fromRangeKey(draftSelection.timeSelection, draftSelection.from, draftSelection.to));
66
+ // Sync local timeRangeSelection when URL state changes externally (e.g., "Switch to 1 minute" button)
67
+ useEffect(() => {
68
+ setTimeRangeSelection(DateTimeRange.fromRangeKey(querySelection.timeSelection, querySelection.from, querySelection.to));
69
+ }, [querySelection.timeSelection, querySelection.from, querySelection.to]);
66
70
  const [queryExpressionString, setQueryExpressionString] = useState(draftSelection.expression);
67
71
  const [advancedModeForQueryBrowser, setAdvancedModeForQueryBrowser] = useState(queryBrowserMode === 'advanced');
68
72
  // Handler to update draft when time range changes
@@ -5,6 +5,7 @@ interface GroupByControlsProps {
5
5
  setGroupByLabels: (labels: string[]) => void;
6
6
  metadataRefetch?: () => Promise<void>;
7
7
  metadataLoading: boolean;
8
+ label?: string;
8
9
  }
9
10
  declare const GroupByControls: React.FC<GroupByControlsProps>;
10
11
  export default GroupByControls;
@@ -1 +1 @@
1
- {"version":3,"file":"GroupByDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ActionButtons/GroupByDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAkBnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
1
+ {"version":3,"file":"GroupByDropdown.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ActionButtons/GroupByDropdown.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAK,MAAM,OAAO,CAAC;AAI1B,UAAU,oBAAoB;IAC5B,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,QAAA,MAAM,eAAe,EAAE,KAAK,CAAC,EAAE,CAAC,oBAAoB,CAoBnD,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -1,6 +1,6 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import GroupByLabelsDropdown from '../GroupByLabelsDropdown';
3
- const GroupByControls = ({ groupBy, labels, setGroupByLabels, metadataRefetch, metadataLoading, }) => {
4
- return (_jsx("div", { className: "relative flex", id: "h-group-by-controls", children: _jsx(GroupByLabelsDropdown, { labels: labels, groupBy: groupBy, setGroupByLabels: setGroupByLabels, metadataRefetch: metadataRefetch, metadataLoading: metadataLoading }) }));
3
+ const GroupByControls = ({ groupBy, labels, setGroupByLabels, metadataRefetch, metadataLoading, label, }) => {
4
+ return (_jsx("div", { className: "relative flex", id: "h-group-by-controls", children: _jsx(GroupByLabelsDropdown, { labels: labels, groupBy: groupBy, setGroupByLabels: setGroupByLabels, metadataRefetch: metadataRefetch, metadataLoading: metadataLoading, label: label }) }));
5
5
  };
6
6
  export default GroupByControls;
@@ -2,13 +2,13 @@ import { ProfilerOnRenderCallback } from 'react';
2
2
  import { QueryServiceClient } from '@parca/client';
3
3
  import { CurrentPathFrame } from '../../../ProfileFlameGraph/FlameGraphArrow/utils';
4
4
  import { ProfileSource } from '../../../ProfileSource';
5
- import type { FlamegraphData, SandwichData, SourceData, TopTableData, VisualizationType } from '../../types/visualization';
5
+ import type { FlamegraphData, SamplesData, SandwichData, SourceData, TopTableData, VisualizationType } from '../../types/visualization';
6
6
  interface GetDashboardItemProps {
7
7
  type: VisualizationType;
8
8
  isHalfScreen: boolean;
9
9
  dimensions: DOMRect | undefined;
10
10
  flamegraphData: FlamegraphData;
11
- flamechartData: FlamegraphData;
11
+ samplesData?: SamplesData;
12
12
  topTableData?: TopTableData;
13
13
  sandwichData: SandwichData;
14
14
  sourceData?: SourceData;
@@ -20,8 +20,9 @@ interface GetDashboardItemProps {
20
20
  perf?: {
21
21
  onRender?: ProfilerOnRenderCallback;
22
22
  };
23
- queryClient?: QueryServiceClient;
23
+ queryClient: QueryServiceClient;
24
+ onSwitchToOneMinute?: () => void;
24
25
  }
25
- export declare const getDashboardItem: ({ type, isHalfScreen, dimensions, flamegraphData, flamechartData, topTableData, sourceData, sandwichData, profileSource, total, filtered, curPathArrow, setNewCurPathArrow, perf, }: GetDashboardItemProps) => JSX.Element;
26
+ export declare const getDashboardItem: ({ type, isHalfScreen, dimensions, flamegraphData, samplesData, topTableData, sourceData, sandwichData, profileSource, total, filtered, curPathArrow, setNewCurPathArrow, perf, queryClient, onSwitchToOneMinute, }: GetDashboardItemProps) => JSX.Element;
26
27
  export {};
27
28
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/DashboardItems/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAW,wBAAwB,EAAC,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAIjD,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAIrD,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EAClB,MAAM,2BAA2B,CAAC;AAEnC,UAAU,qBAAqB;IAC7B,IAAI,EAAE,iBAAiB,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,wBAAwB,CAAC;KACrC,CAAC;IACF,WAAW,CAAC,EAAE,kBAAkB,CAAC;CAClC;AAED,eAAO,MAAM,gBAAgB,GAAI,qLAe9B,qBAAqB,KAAG,GAAG,CAAC,OAgG9B,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/DashboardItems/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAW,wBAAwB,EAAC,MAAM,OAAO,CAAC;AAEzD,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAKjD,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAIrD,OAAO,KAAK,EACV,cAAc,EACd,WAAW,EACX,YAAY,EACZ,UAAU,EACV,YAAY,EACZ,iBAAiB,EAClB,MAAM,2BAA2B,CAAC;AAEnC,UAAU,qBAAqB;IAC7B,IAAI,EAAE,iBAAiB,CAAC;IACxB,YAAY,EAAE,OAAO,CAAC;IACtB,UAAU,EAAE,OAAO,GAAG,SAAS,CAAC;IAChC,cAAc,EAAE,cAAc,CAAC;IAC/B,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,YAAY,EAAE,YAAY,CAAC;IAC3B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,EAAE,aAAa,CAAC;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,kBAAkB,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACvD,IAAI,CAAC,EAAE;QACL,QAAQ,CAAC,EAAE,wBAAwB,CAAC;KACrC,CAAC;IACF,WAAW,EAAE,kBAAkB,CAAC;IAChC,mBAAmB,CAAC,EAAE,MAAM,IAAI,CAAC;CAClC;AAED,eAAO,MAAM,gBAAgB,GAAI,oNAiB9B,qBAAqB,KAAG,GAAG,CAAC,OA6F9B,CAAC"}
@@ -13,11 +13,12 @@ import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
13
13
  // limitations under the License.
14
14
  import { Profiler } from 'react';
15
15
  import { ConditionalWrapper } from '@parca/components';
16
+ import ProfileFlameChart from '../../../ProfileFlameChart';
16
17
  import ProfileFlameGraph from '../../../ProfileFlameGraph';
17
18
  import Sandwich from '../../../Sandwich';
18
19
  import { SourceView } from '../../../SourceView';
19
20
  import { Table } from '../../../Table';
20
- export const getDashboardItem = ({ type, isHalfScreen, dimensions, flamegraphData, flamechartData, topTableData, sourceData, sandwichData, profileSource, total, filtered, curPathArrow, setNewCurPathArrow, perf, }) => {
21
+ export const getDashboardItem = ({ type, isHalfScreen, dimensions, flamegraphData, samplesData, topTableData, sourceData, sandwichData, profileSource, total, filtered, curPathArrow, setNewCurPathArrow, perf, queryClient, onSwitchToOneMinute, }) => {
21
22
  switch (type) {
22
23
  case 'flamegraph':
23
24
  return (_jsx(ConditionalWrapper, { condition: perf?.onRender != null, WrapperComponent: Profiler, wrapperProps: {
@@ -29,11 +30,11 @@ export const getDashboardItem = ({ type, isHalfScreen, dimensions, flamegraphDat
29
30
  : dimensions.width - 16
30
31
  : 0, metadataMappingFiles: flamegraphData.metadataMappingFiles, metadataLoading: flamegraphData.metadataLoading, profileSource: profileSource }) }));
31
32
  case 'flamechart':
32
- return (_jsx(ProfileFlameGraph, { curPathArrow: [], setNewCurPathArrow: () => { }, arrow: flamechartData?.arrow, total: total, filtered: filtered, profileType: profileSource?.ProfileType(), loading: flamechartData.loading, error: flamechartData.error, isHalfScreen: isHalfScreen, width: dimensions?.width !== undefined
33
+ return (_jsx(ProfileFlameChart, { samplesData: samplesData, queryClient: queryClient, profileSource: profileSource, width: dimensions?.width !== undefined
33
34
  ? isHalfScreen
34
35
  ? (dimensions.width - 54) / 2
35
36
  : dimensions.width - 16
36
- : 0, metadataMappingFiles: flamechartData.metadataMappingFiles, metadataLoading: flamechartData.metadataLoading, profileSource: profileSource, isFlameChart: true }));
37
+ : 0, total: total, filtered: filtered, profileType: profileSource?.ProfileType(), isHalfScreen: isHalfScreen, metadataMappingFiles: flamegraphData.metadataMappingFiles, metadataLoading: flamegraphData.metadataLoading, onSwitchToOneMinute: onSwitchToOneMinute }));
37
38
  case 'table':
38
39
  return topTableData != null ? (_jsx(Table, { error: topTableData.error, total: total, filtered: filtered, loading: topTableData.loading, data: topTableData.arrow?.record, unit: topTableData.unit, profileType: profileSource?.ProfileType(), isHalfScreen: isHalfScreen, metadataMappingFiles: flamegraphData.metadataMappingFiles })) : (_jsx(_Fragment, {}));
39
40
  case 'sandwich':
@@ -4,7 +4,8 @@ interface Props {
4
4
  setGroupByLabels: (labels: string[]) => void;
5
5
  metadataRefetch?: () => Promise<void>;
6
6
  metadataLoading: boolean;
7
+ label?: string;
7
8
  }
8
- declare const GroupByLabelsDropdown: ({ labels, groupBy, setGroupByLabels, metadataRefetch, metadataLoading, }: Props) => JSX.Element;
9
+ declare const GroupByLabelsDropdown: ({ labels, groupBy, setGroupByLabels, metadataRefetch, metadataLoading, label, }: Props) => JSX.Element;
9
10
  export default GroupByLabelsDropdown;
10
11
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/GroupByLabelsDropdown/index.tsx"],"names":[],"mappings":"AAuBA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,QAAA,MAAM,qBAAqB,GAAI,0EAM5B,KAAK,KAAG,GAAG,CAAC,OAiFd,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/GroupByLabelsDropdown/index.tsx"],"names":[],"mappings":"AAuBA,UAAU,KAAK;IACb,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACtC,eAAe,EAAE,OAAO,CAAC;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,QAAA,MAAM,qBAAqB,GAAI,iFAO5B,KAAK,KAAG,GAAG,CAAC,OAiFd,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -14,8 +14,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
14
  import { TEST_IDS, testId } from '@parca/test-utils';
15
15
  import { FIELD_LABELS } from '../../../ProfileFlameGraph/FlameGraphArrow';
16
16
  import { SelectWithRefresh } from '../../../SelectWithRefresh';
17
- const GroupByLabelsDropdown = ({ labels, groupBy, setGroupByLabels, metadataRefetch, metadataLoading, }) => {
18
- return (_jsxs("div", { className: "flex flex-col relative", ...testId(TEST_IDS.GROUP_BY_CONTAINER), children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("label", { className: "text-sm", ...testId(TEST_IDS.GROUP_BY_LABEL), children: "Group by" }) }), _jsx(SelectWithRefresh, { isMulti: true, defaultMenuIsOpen: false, defaultValue: undefined, name: "labels", options: labels.map(label => ({ label, value: `${FIELD_LABELS}.${label}` })), className: "parca-select-container text-sm rounded-md bg-white", classNamePrefix: "parca-select", onRefresh: metadataRefetch, refreshTitle: "Refresh label names", refreshTestId: "group-by-refresh-button", menuTestId: TEST_IDS.GROUP_BY_SELECT_FLYOUT, value: groupBy
17
+ const GroupByLabelsDropdown = ({ labels, groupBy, setGroupByLabels, metadataRefetch, metadataLoading, label = 'Group by', }) => {
18
+ return (_jsxs("div", { className: "flex flex-col relative", ...testId(TEST_IDS.GROUP_BY_CONTAINER), children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("label", { className: "text-sm", ...testId(TEST_IDS.GROUP_BY_LABEL), children: label }) }), _jsx(SelectWithRefresh, { isMulti: true, defaultMenuIsOpen: false, defaultValue: undefined, name: "labels", options: labels.map(label => ({ label, value: `${FIELD_LABELS}.${label}` })), className: "parca-select-container text-sm rounded-md bg-white", classNamePrefix: "parca-select", onRefresh: metadataRefetch, refreshTitle: "Refresh label names", refreshTestId: "group-by-refresh-button", menuTestId: TEST_IDS.GROUP_BY_SELECT_FLYOUT, value: (groupBy ?? [])
19
19
  .filter(l => l.startsWith(FIELD_LABELS))
20
20
  .map(l => ({ value: l, label: l.slice(FIELD_LABELS.length + 1) })), onChange: newValue => {
21
21
  setGroupByLabels(newValue.map(option => option.value));
@@ -215,7 +215,7 @@ const MultiLevelDropdown = ({ onSelect, profileType, groupBy, toggleGroupBy, isT
215
215
  icon: 'ph:eye-closed',
216
216
  },
217
217
  ];
218
- return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", ref: dropdownRef, children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "pajamas:preferences", className: "w-4 h-4" }), _jsx("span", { children: "Preferences" })] }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsx(Menu.Items, { className: cx(isTableVizOnly ? 'w-64' : 'w-80', 'absolute z-30 mt-2 py-2 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600', shouldOpenLeft ? 'right-0 origin-top-right' : 'left-0 origin-top-left'), children: menuItems
218
+ return (_jsx("div", { className: "relative inline-block text-left", id: "h-visualisation-toolbar-actions", ref: dropdownRef, children: _jsx(Menu, { children: ({ open, close }) => (_jsxs(_Fragment, { children: [_jsxs(Menu.Button, { className: "flex dark:bg-gray-900 dark:border-gray-600 justify-center w-full px-4 py-2 text-sm font-normal text-gray-600 dark:text-gray-200 bg-white rounded-md focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 border border-gray-200 pr-[1.7rem]", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Icon, { icon: "pajamas:preferences", className: "w-4 h-4" }), _jsx("span", { children: "Preferences" })] }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }), open && (_jsx(Menu.Items, { className: cx(isTableVizOnly ? 'w-64' : 'w-80', 'absolute z-50 mt-2 py-2 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none border dark:bg-gray-900 dark:border-gray-600', shouldOpenLeft ? 'right-0 origin-top-right' : 'left-0 origin-top-left'), children: menuItems
219
219
  .filter(item => item.hide !== undefined && !item.hide)
220
220
  .map((item, index) => (_jsx(MenuItem, { ...item, onSelect: onSelect, closeDropdown: close, activeValueForSortBy: storeSortBy, activeValueForColorBy: colorBy === undefined || colorBy === '' ? 'binary' : colorBy, activeValuesForLevel: groupBy, renderAsDiv: item.renderAsDiv }, index))) }))] })) }) }));
221
221
  };
@@ -19,6 +19,8 @@ export interface VisualisationToolbarProps {
19
19
  preferencesModal?: boolean;
20
20
  profileViewExternalSubActions?: React.ReactNode;
21
21
  setGroupByLabels: (labels: string[]) => void;
22
+ flamechartDimension: string[];
23
+ setFlamechartDimension: (labels: string[]) => void;
22
24
  showVisualizationSelector?: boolean;
23
25
  sandwichFunctionName?: string;
24
26
  alignFunctionName: string;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAmG9D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAkH9D,CAAC"}
@@ -20,17 +20,19 @@ export const SandwichFlameGraphToolbar = ({ resetSandwichFunctionName, sandwichF
20
20
  return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName === undefined || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
21
21
  };
22
22
  const Divider = () => (_jsx("div", { className: "border-t mt-4 border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" }));
23
- export const VisualisationToolbar = ({ groupBy, toggleGroupBy, setGroupByLabels, profileType, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, showVisualizationSelector = true, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, metadata: { labels: groupByLabels, refetch: metadataRefetch, loading: metadataLoading }, }) => {
23
+ export const VisualisationToolbar = ({ groupBy, toggleGroupBy, setGroupByLabels, flamechartDimension, setFlamechartDimension, profileType, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, showVisualizationSelector = true, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, metadata: { labels: groupByLabels, refetch: metadataRefetch, loading: metadataLoading }, }) => {
24
24
  const { dashboardItems } = useDashboard();
25
25
  const isTableViz = dashboardItems?.includes('table');
26
26
  const isTableVizOnly = dashboardItems?.length === 1 && isTableViz;
27
27
  const isGraphViz = dashboardItems?.includes('flamegraph');
28
28
  const isGraphVizOnly = dashboardItems?.length === 1 && isGraphViz;
29
+ const isFlamechartViz = dashboardItems?.includes('flamechart');
30
+ const isFlamechartVizOnly = dashboardItems?.length === 1 && isFlamechartViz;
29
31
  const req = profileSource?.QueryRequest();
30
32
  if (req !== null && req !== undefined) {
31
33
  req.groupBy = {
32
34
  fields: groupBy ?? [],
33
35
  };
34
36
  }
35
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full justify-between items-start gap-2", children: [_jsxs("div", { className: "flex gap-2 items-start", children: [isGraphViz && (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, labels: groupByLabels, setGroupByLabels: setGroupByLabels, metadataRefetch: metadataRefetch, metadataLoading: metadataLoading }), _jsx(InvertCallStack, {})] })), _jsxs("div", { className: "flex mt-5", children: [_jsx(ProfileFilters, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null] })] }), _jsxs("div", { className: "flex gap-2 mt-5", children: [_jsx(MultiLevelDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, profileType: profileType, onSelect: () => { }, isTableVizOnly: isTableVizOnly, alignFunctionName: alignFunctionName, setAlignFunctionName: setAlignFunctionName, colorBy: colorBy, setColorBy: setColorBy }), _jsx(ShareButton, { profileSource: profileSource, queryClient: queryClient, queryRequest: req, onDownloadPProf: onDownloadPProf, pprofdownloading: pprofdownloading ?? false, profileViewExternalSubActions: profileViewExternalSubActions }), showVisualizationSelector ? _jsx(ViewSelector, { profileSource: profileSource }) : null] })] }), isGraphVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(FlameGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath })] })), isTableVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(TableToolbar, { profileType: profileType, total: total, filtered: filtered })] }))] }));
37
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full justify-between items-start gap-2", children: [_jsxs("div", { className: "flex gap-2 items-start", children: [isGraphViz && (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, labels: groupByLabels, setGroupByLabels: setGroupByLabels, metadataRefetch: metadataRefetch, metadataLoading: metadataLoading }), _jsx(InvertCallStack, {})] })), isFlamechartViz && (_jsx(GroupByDropdown, { groupBy: flamechartDimension, labels: groupByLabels, setGroupByLabels: setFlamechartDimension, metadataRefetch: metadataRefetch, metadataLoading: metadataLoading, label: "Samples group by" })), _jsxs("div", { className: "flex mt-5", children: [!isFlamechartVizOnly && _jsx(ProfileFilters, {}), profileViewExternalSubActions != null ? profileViewExternalSubActions : null] })] }), _jsxs("div", { className: "flex gap-2 mt-5", children: [_jsx(MultiLevelDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, profileType: profileType, onSelect: () => { }, isTableVizOnly: isTableVizOnly, alignFunctionName: alignFunctionName, setAlignFunctionName: setAlignFunctionName, colorBy: colorBy, setColorBy: setColorBy }), _jsx(ShareButton, { profileSource: profileSource, queryClient: queryClient, queryRequest: req, onDownloadPProf: onDownloadPProf, pprofdownloading: pprofdownloading ?? false, profileViewExternalSubActions: profileViewExternalSubActions }), showVisualizationSelector ? _jsx(ViewSelector, { profileSource: profileSource }) : null] })] }), isGraphVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(FlameGraphToolbar, { curPath: curPath, setNewCurPath: setNewCurPath })] })), isTableVizOnly && (_jsxs(_Fragment, { children: [_jsx(Divider, {}), _jsx(TableToolbar, { profileType: profileType, total: total, filtered: filtered })] }))] }));
36
38
  };
@@ -0,0 +1,16 @@
1
+ import { ProfileType } from '@parca/parser';
2
+ /**
3
+ * Auto-selects the best flamechart "group by" dimension on first load.
4
+ *
5
+ * For On-GPU profiles:
6
+ * - Selects all available from: ['node', 'gpu', 'stream']
7
+ *
8
+ * For On-CPU profiles:
9
+ * - Priority: cpu > cpuid > thread > thread_id
10
+ * - Adds 'node' alongside the primary dimension if available
11
+ *
12
+ * For all other profile types:
13
+ * - No auto-selection
14
+ */
15
+ export declare const useAutoSelectDimension: (metadataLabels: string[] | undefined, flamechartDimension: string[] | undefined, setFlamechartDimension: (v: string[]) => void, profileType?: ProfileType) => void;
16
+ //# sourceMappingURL=useAutoSelectDimension.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAutoSelectDimension.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useAutoSelectDimension.ts"],"names":[],"mappings":"AAeA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAwB1C;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,sBAAsB,GACjC,gBAAgB,MAAM,EAAE,GAAG,SAAS,EACpC,qBAAqB,MAAM,EAAE,GAAG,SAAS,EACzC,wBAAwB,CAAC,CAAC,EAAE,MAAM,EAAE,KAAK,IAAI,EAC7C,cAAc,WAAW,KACxB,IAgCF,CAAC"}
@@ -0,0 +1,75 @@
1
+ // Copyright 2022 The Parca Authors
2
+ // Licensed under the Apache License, Version 2.0 (the "License");
3
+ // you may not use this file except in compliance with the License.
4
+ // You may obtain a copy of the License at
5
+ //
6
+ // http://www.apache.org/licenses/LICENSE-2.0
7
+ //
8
+ // Unless required by applicable law or agreed to in writing, software
9
+ // distributed under the License is distributed on an "AS IS" BASIS,
10
+ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11
+ // See the License for the specific language governing permissions and
12
+ // limitations under the License.
13
+ import { useEffect, useRef } from 'react';
14
+ import { wellKnownProfiles } from '../../ProfileTypeSelector';
15
+ const CPU_PREFERRED_DIMENSIONS = ['cpu', 'cpuid', 'thread', 'thread_id'];
16
+ const GPU_DIMENSIONS = ['node', 'gpu', 'stream'];
17
+ const getWellKnownProfileName = (profileType) => {
18
+ if (profileType == null)
19
+ return undefined;
20
+ const key = profileType.toString();
21
+ return wellKnownProfiles[key]?.name;
22
+ };
23
+ const isOnGpuProfile = (profileType) => {
24
+ const wellKnownName = getWellKnownProfileName(profileType);
25
+ return wellKnownName === 'On-GPU';
26
+ };
27
+ const isOnCpuProfile = (profileType) => {
28
+ const wellKnownName = getWellKnownProfileName(profileType);
29
+ return wellKnownName === 'On-CPU';
30
+ };
31
+ /**
32
+ * Auto-selects the best flamechart "group by" dimension on first load.
33
+ *
34
+ * For On-GPU profiles:
35
+ * - Selects all available from: ['node', 'gpu', 'stream']
36
+ *
37
+ * For On-CPU profiles:
38
+ * - Priority: cpu > cpuid > thread > thread_id
39
+ * - Adds 'node' alongside the primary dimension if available
40
+ *
41
+ * For all other profile types:
42
+ * - No auto-selection
43
+ */
44
+ export const useAutoSelectDimension = (metadataLabels, flamechartDimension, setFlamechartDimension, profileType) => {
45
+ const hasAutoSelected = useRef(false);
46
+ useEffect(() => {
47
+ if (hasAutoSelected.current)
48
+ return;
49
+ if (metadataLabels == null || metadataLabels.length === 0)
50
+ return;
51
+ if ((flamechartDimension ?? []).length > 0) {
52
+ hasAutoSelected.current = true;
53
+ return;
54
+ }
55
+ if (isOnGpuProfile(profileType)) {
56
+ const availableGpuDims = GPU_DIMENSIONS.filter(d => metadataLabels.includes(d));
57
+ if (availableGpuDims.length > 0) {
58
+ setFlamechartDimension(availableGpuDims.map(d => `labels.${d}`));
59
+ hasAutoSelected.current = true;
60
+ return;
61
+ }
62
+ }
63
+ if (isOnCpuProfile(profileType)) {
64
+ const hasNode = metadataLabels.includes('node');
65
+ for (const name of CPU_PREFERRED_DIMENSIONS) {
66
+ if (metadataLabels.includes(name)) {
67
+ const dims = hasNode ? ['node', name] : [name];
68
+ setFlamechartDimension(dims.map(d => `labels.${d}`));
69
+ hasAutoSelected.current = true;
70
+ return;
71
+ }
72
+ }
73
+ }
74
+ }, [metadataLabels, flamechartDimension, setFlamechartDimension, profileType]);
75
+ };
@@ -9,6 +9,8 @@ export declare const useVisualizationState: () => {
9
9
  setGroupBy: (keys: string[]) => void;
10
10
  toggleGroupBy: (key: string) => void;
11
11
  setGroupByLabels: (labels: string[]) => void;
12
+ flamechartDimension: string[];
13
+ setFlamechartDimension: (labels: string[]) => void;
12
14
  sandwichFunctionName: string | undefined;
13
15
  setSandwichFunctionName: (sandwichFunctionName: string | undefined) => void;
14
16
  resetSandwichFunctionName: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAG/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAiH/C,CAAC"}
1
+ {"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAG/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAgI/C,CAAC"}
@@ -35,6 +35,9 @@ export const useVisualizationState = () => {
35
35
  alwaysReturnArray: true,
36
36
  });
37
37
  const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
38
+ const [flamechartDimension, setStoreFlamechartDimension] = useURLState('flamechart_dimension', {
39
+ alwaysReturnArray: true,
40
+ });
38
41
  const resetFlameGraphState = useResetFlameGraphState();
39
42
  const batchUpdates = useURLStateBatch();
40
43
  const levelsOfProfiling = useMemo(() => [
@@ -66,6 +69,9 @@ export const useVisualizationState = () => {
66
69
  resetFlameGraphState();
67
70
  });
68
71
  }, [groupBy, setGroupBy, resetFlameGraphState, batchUpdates]);
72
+ const setFlamechartDimension = useCallback((labels) => {
73
+ setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
74
+ }, [setStoreFlamechartDimension]);
69
75
  const resetSandwichFunctionName = useCallback(() => {
70
76
  setSandwichFunctionName(undefined);
71
77
  }, [setSandwichFunctionName]);
@@ -87,6 +93,8 @@ export const useVisualizationState = () => {
87
93
  setGroupBy,
88
94
  toggleGroupBy,
89
95
  setGroupByLabels,
96
+ flamechartDimension,
97
+ setFlamechartDimension,
90
98
  sandwichFunctionName,
91
99
  setSandwichFunctionName,
92
100
  resetSandwichFunctionName,
@@ -1,3 +1,3 @@
1
1
  import type { ProfileViewProps } from './types/visualization';
2
- export declare const ProfileView: ({ total, filtered, flamegraphData, flamechartData, topTableData, sourceData, profileSource, queryClient, onDownloadPProf, pprofDownloading, compare, showVisualizationSelector, sandwichData, }: ProfileViewProps) => JSX.Element;
2
+ export declare const ProfileView: ({ total, filtered, flamegraphData, samplesData, topTableData, sourceData, profileSource, queryClient, onDownloadPProf, pprofDownloading, compare, showVisualizationSelector, sandwichData, onSwitchToOneMinute, }: ProfileViewProps) => JSX.Element;
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AA+BA,OAAO,KAAK,EAAC,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE/E,eAAO,MAAM,WAAW,GAAI,iMAczB,gBAAgB,KAAG,GAAG,CAAC,OAsIzB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AAgCA,OAAO,KAAK,EAAC,gBAAgB,EAAoB,MAAM,uBAAuB,CAAC;AAE/E,eAAO,MAAM,WAAW,GAAI,mNAezB,gBAAgB,KAAG,GAAG,CAAC,OAkJzB,CAAC"}
@@ -21,12 +21,14 @@ import { ProfileHeader } from './components/ProfileHeader';
21
21
  import { FlameGraphToolbar, SandwichFlameGraphToolbar, TableToolbar, VisualisationToolbar, } from './components/Toolbars';
22
22
  import { DashboardProvider } from './context/DashboardContext';
23
23
  import { ProfileViewContextProvider } from './context/ProfileViewContext';
24
+ import { useAutoSelectDimension } from './hooks/useAutoSelectDimension';
24
25
  import { useProfileMetadata } from './hooks/useProfileMetadata';
25
26
  import { useVisualizationState } from './hooks/useVisualizationState';
26
- export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, topTableData, sourceData, profileSource, queryClient, onDownloadPProf, pprofDownloading, compare, showVisualizationSelector, sandwichData, }) => {
27
+ export const ProfileView = ({ total, filtered, flamegraphData, samplesData, topTableData, sourceData, profileSource, queryClient, onDownloadPProf, pprofDownloading, compare, showVisualizationSelector, sandwichData, onSwitchToOneMinute, }) => {
27
28
  const { timezone, perf, profileViewExternalMainActions, preferencesModal, profileViewExternalSubActions, } = useParcaContext();
28
29
  const { ref, dimensions } = useContainerDimensions();
29
- const { curPathArrow, setCurPathArrow, colorStackLegend, colorBy, setColorBy, groupBy, toggleGroupBy, setGroupByLabels, sandwichFunctionName, resetSandwichFunctionName, alignFunctionName, setAlignFunctionName, } = useVisualizationState();
30
+ const { curPathArrow, setCurPathArrow, colorStackLegend, colorBy, setColorBy, groupBy, toggleGroupBy, setGroupByLabels, flamechartDimension, setFlamechartDimension, sandwichFunctionName, resetSandwichFunctionName, alignFunctionName, setAlignFunctionName, } = useVisualizationState();
31
+ useAutoSelectDimension(flamegraphData.metadataLabels, flamechartDimension, setFlamechartDimension, profileSource?.ProfileType());
30
32
  const { colorMappings } = useProfileMetadata({
31
33
  flamegraphArrow: flamegraphData.arrow,
32
34
  metadataMappingFiles: flamegraphData.metadataMappingFiles,
@@ -43,7 +45,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, t
43
45
  isHalfScreen,
44
46
  dimensions,
45
47
  flamegraphData,
46
- flamechartData,
48
+ samplesData,
47
49
  topTableData,
48
50
  sourceData,
49
51
  profileSource,
@@ -53,6 +55,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, t
53
55
  setNewCurPathArrow: setCurPathArrow,
54
56
  perf,
55
57
  queryClient,
58
+ onSwitchToOneMinute,
56
59
  });
57
60
  };
58
61
  const actionButtons = {
@@ -65,5 +68,5 @@ export const ProfileView = ({ total, filtered, flamegraphData, flamechartData, t
65
68
  labels: flamegraphData.metadataLabels ?? [],
66
69
  refetch: flamegraphData.metadataRefetch,
67
70
  loading: flamegraphData.metadataLoading,
68
- }, preferencesModal: preferencesModal, profileViewExternalSubActions: profileViewExternalSubActions, setGroupByLabels: setGroupByLabels, showVisualizationSelector: showVisualizationSelector, sandwichFunctionName: sandwichFunctionName, alignFunctionName: alignFunctionName, setAlignFunctionName: setAlignFunctionName, colorBy: colorBy, setColorBy: setColorBy }), isColorStackLegendEnabled && (_jsx(ColorStackLegend, { compareMode: compareMode, mappings: colorMappings, loading: flamegraphData.metadataLoading })), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DashboardLayout, { getDashboardItemByType: getDashboardItemByType, actionButtons: actionButtons }) })] }) }) }));
71
+ }, preferencesModal: preferencesModal, profileViewExternalSubActions: profileViewExternalSubActions, setGroupByLabels: setGroupByLabels, flamechartDimension: flamechartDimension, setFlamechartDimension: setFlamechartDimension, showVisualizationSelector: showVisualizationSelector, sandwichFunctionName: sandwichFunctionName, alignFunctionName: alignFunctionName, setAlignFunctionName: setAlignFunctionName, colorBy: colorBy, setColorBy: setColorBy }), isColorStackLegendEnabled && (_jsx(ColorStackLegend, { compareMode: compareMode, mappings: colorMappings, loading: flamegraphData.metadataLoading })), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DashboardLayout, { getDashboardItemByType: getDashboardItemByType, actionButtons: actionButtons }) })] }) }) }));
69
72
  };
@@ -1,5 +1,6 @@
1
1
  import { RpcError } from '@protobuf-ts/runtime-rpc';
2
- import { FlamegraphArrow, QueryServiceClient, Source, TableArrow } from '@parca/client';
2
+ import { FlamegraphArrow, LabelSet, QueryServiceClient, Source, TableArrow } from '@parca/client';
3
+ import { DataPoint } from '../../ProfileFlameChart/SamplesStrips/SamplesGraph';
3
4
  import { ProfileSource } from '../../ProfileSource';
4
5
  export interface FlamegraphData {
5
6
  loading: boolean;
@@ -29,20 +30,31 @@ export interface SandwichData {
29
30
  callees: FlamegraphData;
30
31
  callers: FlamegraphData;
31
32
  }
33
+ export interface SamplesSeries {
34
+ labelset: LabelSet;
35
+ data: DataPoint[];
36
+ }
37
+ export interface SamplesData {
38
+ loading: boolean;
39
+ series?: SamplesSeries[];
40
+ error: RpcError | null;
41
+ stepMs?: number;
42
+ }
32
43
  export type VisualizationType = 'flamegraph' | 'callgraph' | 'table' | 'source' | 'flamechart' | 'sandwich';
33
44
  export interface ProfileViewProps {
34
45
  total: bigint;
35
46
  filtered: bigint;
36
47
  flamegraphData: FlamegraphData;
37
- flamechartData: FlamegraphData;
48
+ samplesData?: SamplesData;
38
49
  sandwichData: SandwichData;
39
50
  topTableData?: TopTableData;
40
51
  sourceData?: SourceData;
41
52
  profileSource: ProfileSource;
42
- queryClient?: QueryServiceClient;
53
+ queryClient: QueryServiceClient;
43
54
  compare?: boolean;
44
55
  onDownloadPProf: () => void;
45
56
  pprofDownloading?: boolean;
46
57
  showVisualizationSelector?: boolean;
58
+ onSwitchToOneMinute?: () => void;
47
59
  }
48
60
  //# sourceMappingURL=visualization.d.ts.map