@parca/profile 0.16.411 → 0.16.413

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 (33) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  3. package/dist/ProfileExplorer/ProfileExplorerCompare.js +1 -1
  4. package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts.map +1 -1
  5. package/dist/ProfileExplorer/ProfileExplorerSingle.js +1 -1
  6. package/dist/ProfileExplorer/index.d.ts.map +1 -1
  7. package/dist/ProfileExplorer/index.js +3 -1
  8. package/dist/ProfileMetricsGraph/index.d.ts +5 -2
  9. package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
  10. package/dist/ProfileMetricsGraph/index.js +9 -20
  11. package/dist/ProfileSelector/index.d.ts +3 -1
  12. package/dist/ProfileSelector/index.d.ts.map +1 -1
  13. package/dist/ProfileSelector/index.js +31 -6
  14. package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
  15. package/dist/ProfileSelector/useAutoQuerySelector.js +6 -0
  16. package/dist/styles.css +1 -1
  17. package/dist/useSumBy.d.ts +8 -0
  18. package/dist/useSumBy.d.ts.map +1 -0
  19. package/dist/{ProfileMetricsGraph/useSumBy.js → useSumBy.js} +16 -18
  20. package/package.json +2 -2
  21. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +2 -0
  22. package/src/ProfileExplorer/ProfileExplorerSingle.tsx +1 -0
  23. package/src/ProfileExplorer/index.tsx +4 -0
  24. package/src/ProfileMetricsGraph/index.tsx +9 -30
  25. package/src/ProfileSelector/index.tsx +67 -3
  26. package/src/ProfileSelector/useAutoQuerySelector.ts +9 -1
  27. package/src/{ProfileMetricsGraph/useSumBy.ts → useSumBy.ts} +29 -23
  28. package/dist/ProfileMetricsGraph/Toolbar/index.d.ts +0 -9
  29. package/dist/ProfileMetricsGraph/Toolbar/index.d.ts.map +0 -1
  30. package/dist/ProfileMetricsGraph/Toolbar/index.js +0 -29
  31. package/dist/ProfileMetricsGraph/useSumBy.d.ts +0 -4
  32. package/dist/ProfileMetricsGraph/useSumBy.d.ts.map +0 -1
  33. package/src/ProfileMetricsGraph/Toolbar/index.tsx +0 -94
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.413](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.412...@parca/profile@0.16.413) (2024-07-22)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.412](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.411...@parca/profile@0.16.412) (2024-07-16)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.16.411](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.410...@parca/profile@0.16.411) (2024-07-15)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileExplorerCompare.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/ProfileExplorerCompare.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAGjD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAoB,gBAAgB,EAAsB,MAAM,IAAI,CAAC;AAC5E,OAAwB,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAEnE,UAAU,2BAA2B;IACnC,WAAW,EAAE,kBAAkB,CAAC;IAEhC,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,YAAY,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,QAAA,MAAM,sBAAsB,+IAYzB,2BAA2B,KAAG,GAAG,CAAC,OAsEpC,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
1
+ {"version":3,"file":"ProfileExplorerCompare.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/ProfileExplorerCompare.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAGjD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAoB,gBAAgB,EAAsB,MAAM,IAAI,CAAC;AAC5E,OAAwB,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAEnE,UAAU,2BAA2B;IACnC,WAAW,EAAE,kBAAkB,CAAC;IAEhC,MAAM,EAAE,cAAc,CAAC;IACvB,MAAM,EAAE,cAAc,CAAC;IACvB,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,QAAQ,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAClC,YAAY,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,YAAY,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC9C,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,QAAA,MAAM,sBAAsB,+IAYzB,2BAA2B,KAAG,GAAG,CAAC,OAwEpC,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
@@ -12,6 +12,6 @@ const ProfileExplorerCompare = ({ queryClient, queryA, queryB, profileA, profile
12
12
  };
13
13
  const [compareAbsolute] = useURLState({ param: 'compare_absolute', navigateTo });
14
14
  const [functionFilter] = useURLState({ param: 'filter_by_function', navigateTo });
15
- return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryA, profileSelection: profileA, selectProfile: selectProfileA, selectQuery: selectQueryA, closeProfile: closeProfileA, enforcedProfileName: '', comparing: true, navigateTo: navigateTo }) }), _jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryB, profileSelection: profileB, selectProfile: selectProfileB, selectQuery: selectQueryB, closeProfile: closeProfileB, enforcedProfileName: Query.parse(queryA.expression).profileName(), comparing: true, navigateTo: navigateTo }) })] }), _jsx("div", { className: "grid grid-cols-1", children: profileA != null && profileB != null ? (_jsx("div", { children: _jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { navigateTo: navigateTo, queryClient: queryClient, profileSource: new ProfileDiffSource(profileA.ProfileSource(), profileB.ProfileSource(), Array.isArray(functionFilter) ? functionFilter[0] : functionFilter, compareAbsolute === 'true') }) }) })) : (_jsx("div", { children: _jsx("div", { className: "my-20 text-center", children: _jsx("p", { children: "Select a profile on both sides." }) }) })) })] }));
15
+ return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex justify-between gap-2", children: [_jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryA, profileSelection: profileA, selectProfile: selectProfileA, selectQuery: selectQueryA, closeProfile: closeProfileA, enforcedProfileName: '', comparing: true, navigateTo: navigateTo, suffix: "_a" }) }), _jsx(Card, { className: "mt-2 p-2", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: queryB, profileSelection: profileB, selectProfile: selectProfileB, selectQuery: selectQueryB, closeProfile: closeProfileB, enforcedProfileName: Query.parse(queryA.expression).profileName(), comparing: true, navigateTo: navigateTo, suffix: "_b" }) })] }), _jsx("div", { className: "grid grid-cols-1", children: profileA != null && profileB != null ? (_jsx("div", { children: _jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { navigateTo: navigateTo, queryClient: queryClient, profileSource: new ProfileDiffSource(profileA.ProfileSource(), profileB.ProfileSource(), Array.isArray(functionFilter) ? functionFilter[0] : functionFilter, compareAbsolute === 'true') }) }) })) : (_jsx("div", { children: _jsx("div", { className: "my-20 text-center", children: _jsx("p", { children: "Select a profile on both sides." }) }) })) })] }));
16
16
  };
17
17
  export default ProfileExplorerCompare;
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileExplorerSingle.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/ProfileExplorerSingle.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAC,gBAAgB,EAAsB,MAAM,IAAI,CAAC;AACzD,OAAwB,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAEnE,UAAU,0BAA0B;IAClC,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,QAAA,MAAM,qBAAqB,6EAOxB,0BAA0B,KAAG,GAAG,CAAC,OA6BnC,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
1
+ {"version":3,"file":"ProfileExplorerSingle.d.ts","sourceRoot":"","sources":["../../src/ProfileExplorer/ProfileExplorerSingle.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,KAAK,EAAC,gBAAgB,EAAC,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAC,gBAAgB,EAAsB,MAAM,IAAI,CAAC;AACzD,OAAwB,EAAC,cAAc,EAAC,MAAM,oBAAoB,CAAC;AAEnE,UAAU,0BAA0B;IAClC,WAAW,EAAE,kBAAkB,CAAC;IAChC,KAAK,EAAE,cAAc,CAAC;IACtB,WAAW,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,aAAa,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IAClD,OAAO,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACjC,UAAU,EAAE,gBAAgB,CAAC;CAC9B;AAED,QAAA,MAAM,qBAAqB,6EAOxB,0BAA0B,KAAG,GAAG,CAAC,OA8BnC,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
@@ -3,6 +3,6 @@ import { Card } from '@parca/components';
3
3
  import { ProfileViewWithData } from '..';
4
4
  import ProfileSelector from '../ProfileSelector';
5
5
  const ProfileExplorerSingle = ({ queryClient, query, selectQuery, selectProfile, profile, navigateTo, }) => {
6
- return (_jsxs(_Fragment, { children: [_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: query, selectQuery: selectQuery, selectProfile: selectProfile, closeProfile: () => { }, profileSelection: profile, comparing: false, enforcedProfileName: '', navigateTo: navigateTo }) }), profile != null ? (_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { queryClient: queryClient, profileSource: profile.ProfileSource(), navigateTo: navigateTo }) })) : (_jsx(_Fragment, {}))] }));
6
+ return (_jsxs(_Fragment, { children: [_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileSelector, { queryClient: queryClient, querySelection: query, selectQuery: selectQuery, selectProfile: selectProfile, closeProfile: () => { }, profileSelection: profile, comparing: false, enforcedProfileName: '', navigateTo: navigateTo, suffix: "_a" }) }), profile != null ? (_jsx(Card, { className: "mt-2 px-6 py-4", children: _jsx(ProfileViewWithData, { queryClient: queryClient, profileSource: profile.ProfileSource(), navigateTo: navigateTo }) })) : (_jsx(_Fragment, {}))] }));
7
7
  };
8
8
  export default ProfileExplorerSingle;
@@ -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;AA4UF,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;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"}
@@ -66,7 +66,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
66
66
  }
67
67
  }, [profileTypesError, onError]);
68
68
  /* eslint-disable @typescript-eslint/naming-convention */
69
- let { from_a, to_a, merge_from_a, merge_to_a, time_selection_a, compare_a, from_b, to_b, merge_from_b, merge_to_b, time_selection_b, compare_b, filter_by_function, dashboard_items, } = queryParams;
69
+ let { from_a, to_a, merge_from_a, merge_to_a, time_selection_a, compare_a, sum_by_a, from_b, to_b, merge_from_b, merge_to_b, time_selection_b, compare_b, sum_by_b, filter_by_function, dashboard_items, } = queryParams;
70
70
  // eslint-disable-next-line @typescript-eslint/naming-convention
71
71
  const expression_a = getExpressionAsAString(queryParams.expression_a);
72
72
  // eslint-disable-next-line @typescript-eslint/naming-convention
@@ -134,6 +134,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
134
134
  from: parseInt(from_a),
135
135
  to: parseInt(to_a),
136
136
  timeSelection: time_selection_a,
137
+ sumBy: sum_by_a,
137
138
  };
138
139
  // Show the SingleProfileExplorer when not comparing
139
140
  if (compare_a !== 'true' && compare_b !== 'true') {
@@ -175,6 +176,7 @@ const ProfileExplorerApp = ({ queryClient, queryParams, navigateTo, }) => {
175
176
  from: parseInt(from_b),
176
177
  to: parseInt(to_b),
177
178
  timeSelection: time_selection_b,
179
+ sumBy: sum_by_b,
178
180
  };
179
181
  const selectQueryA = (q) => {
180
182
  const mergeParams = q.mergeFrom !== undefined && q.mergeTo !== undefined
@@ -9,9 +9,12 @@ export declare const ProfileMetricsEmptyState: ({ message }: ProfileMetricsEmpty
9
9
  interface ProfileMetricsGraphProps {
10
10
  queryClient: QueryServiceClient;
11
11
  queryExpression: string;
12
+ dirtyQueryExpression: string;
12
13
  profile: ProfileSelection | null;
13
14
  from: number;
14
15
  to: number;
16
+ sumByLoading: boolean;
17
+ sumBy: string[];
15
18
  setTimeRange: (range: DateTimeRange) => void;
16
19
  addLabelMatcher: (labels: {
17
20
  key: string;
@@ -28,7 +31,7 @@ export interface IQueryRangeState {
28
31
  isLoading: boolean;
29
32
  error: RpcError | null;
30
33
  }
31
- export declare const useQueryRange: (client: QueryServiceClient, queryExpression: string, start: number, end: number, sumBy?: string[], skip?: boolean) => IQueryRangeState;
32
- declare const ProfileMetricsGraph: ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing, }: ProfileMetricsGraphProps) => JSX.Element;
34
+ export declare const useQueryRange: (client: QueryServiceClient, queryExpression: string, start: number, end: number, sumBy: string[], skip?: boolean) => IQueryRangeState;
35
+ declare const ProfileMetricsGraph: ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing, sumBy, sumByLoading, }: ProfileMetricsGraphProps) => JSX.Element;
33
36
  export default ProfileMetricsGraph;
34
37
  //# sourceMappingURL=index.d.ts.map
@@ -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;AAQ5D,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,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,UACJ,MAAM,EAAE,qBAEd,gBA+CF,CAAC;AAEF,QAAA,MAAM,mBAAmB,iHAUtB,wBAAwB,KAAG,GAAG,CAAC,OA4GjC,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,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,4 +1,4 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
2
  // Copyright 2022 The Parca Authors
3
3
  // Licensed under the Apache License, Version 2.0 (the "License");
4
4
  // you may not use this file except in compliance with the License.
@@ -17,12 +17,9 @@ import { Duration, Timestamp } from '@parca/client';
17
17
  import { MetricsGraphSkeleton, useGrpcMetadata, useParcaContext, useURLState, } from '@parca/components';
18
18
  import { Query } from '@parca/parser';
19
19
  import { capitalizeOnlyFirstLetter, getStepDuration } from '@parca/utilities';
20
- import { useLabelNames } from '../MatchersInput';
21
20
  import MetricsGraph from '../MetricsGraph';
22
21
  import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
23
22
  import useGrpcQuery from '../useGrpcQuery';
24
- import { Toolbar } from './Toolbar';
25
- import { DEFAULT_EMPTY_SUM_BY, useSumBy } from './useSumBy';
26
23
  const ErrorContent = ({ errorMessage }) => {
27
24
  return (_jsx("div", { className: "relative rounded border border-red-400 bg-red-100 px-4 py-3 text-red-700", role: "alert", children: _jsx("span", { className: "block sm:inline", children: errorMessage }) }));
28
25
  };
@@ -37,7 +34,7 @@ const getStepCountFromScreenWidth = (pixelsPerPoint) => {
37
34
  width = width - (20 + 24 + 68) * 2;
38
35
  return Math.round(width / pixelsPerPoint);
39
36
  };
40
- export const useQueryRange = (client, queryExpression, start, end, sumBy = DEFAULT_EMPTY_SUM_BY, skip = false) => {
37
+ export const useQueryRange = (client, queryExpression, start, end, sumBy, skip = false) => {
41
38
  const metadata = useGrpcMetadata();
42
39
  const { navigateTo } = useParcaContext();
43
40
  const [stepCountStr, setStepCount] = useURLState({ param: 'step_count', navigateTo });
@@ -71,19 +68,14 @@ export const useQueryRange = (client, queryExpression, start, end, sumBy = DEFAU
71
68
  },
72
69
  options: {
73
70
  retry: false,
74
- enabled: !skip && sumBy !== DEFAULT_EMPTY_SUM_BY,
71
+ enabled: !skip,
75
72
  staleTime: 1000 * 60 * 5, // 5 minutes
76
73
  },
77
74
  });
78
75
  return { isLoading, error: error, response: data ?? null };
79
76
  };
80
- const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing = false, }) => {
81
- const profileType = useMemo(() => {
82
- return Query.parse(queryExpression).profileType();
83
- }, [queryExpression]);
84
- const { loading: labelNamesLoading, result: labelNamesResult } = useLabelNames(queryClient, profileType.toString() ?? '', from, to);
85
- const [sumBy, setSumBy] = useSumBy(profileType, labelNamesResult.response?.labelNames);
86
- const { isLoading: metricsGraphLoading, response, error, } = useQueryRange(queryClient, queryExpression, from, to, sumBy, labelNamesLoading);
77
+ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to, setTimeRange, addLabelMatcher, onPointClick, comparing = false, sumBy, sumByLoading, }) => {
78
+ const { isLoading: metricsGraphLoading, response, error, } = useQueryRange(queryClient, queryExpression, from, to, sumBy, sumByLoading);
87
79
  const { onError, perf, authenticationErrorMessage, isDarkMode } = useParcaContext();
88
80
  const { width, height, margin, heightStyle } = useMetricsGraphDimensions(comparing);
89
81
  useEffect(() => {
@@ -99,10 +91,7 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
99
91
  }, [perf, response]);
100
92
  const series = response?.series;
101
93
  const dataAvailable = series !== null && series !== undefined && series?.length > 0;
102
- const loading = metricsGraphLoading || labelNamesLoading;
103
- if (!labelNamesLoading && labelNamesResult?.error?.message != null) {
104
- return (_jsx(ErrorContent, { errorMessage: capitalizeOnlyFirstLetter(labelNamesResult.error.message) }));
105
- }
94
+ const loading = metricsGraphLoading;
106
95
  if (!metricsGraphLoading && error !== null) {
107
96
  if (authenticationErrorMessage !== undefined && error.code === 'UNAUTHENTICATED') {
108
97
  return _jsx(ErrorContent, { errorMessage: authenticationErrorMessage });
@@ -118,8 +107,8 @@ const ProfileMetricsGraph = ({ queryClient, queryExpression, profile, from, to,
118
107
  sampleUnit = Query.parse(queryExpression).profileType().sampleUnit;
119
108
  }
120
109
  }
121
- return (_jsx(AnimatePresence, { children: _jsxs(motion.div, { className: "h-full w-full relative", initial: { display: 'none', opacity: 0 }, animate: { display: 'block', opacity: 1 }, transition: { duration: 0.5 }, children: [_jsx(Toolbar, { sumBy: sumBy, setSumBy: setSumBy, labels: labelNamesResult.response?.labelNames ?? [] }), loading ? (_jsx(MetricsGraphSkeleton, { heightStyle: heightStyle, isDarkMode: isDarkMode })) : dataAvailable ? (_jsx(MetricsGraph, { data: series, from: from, to: to, profile: profile, setTimeRange: setTimeRange, onSampleClick: (timestamp, _value, labels, duration) => {
122
- onPointClick(timestamp, labels, queryExpression, duration);
123
- }, addLabelMatcher: addLabelMatcher, sampleUnit: sampleUnit, height: height, width: width, margin: margin })) : (_jsx(ProfileMetricsEmptyState, { message: "No data found. Try a different query." }))] }, "metrics-graph-loaded") }));
110
+ return (_jsx(AnimatePresence, { children: _jsx(motion.div, { className: "h-full w-full relative", initial: { display: 'none', opacity: 0 }, animate: { display: 'block', opacity: 1 }, transition: { duration: 0.5 }, children: loading ? (_jsx(MetricsGraphSkeleton, { heightStyle: heightStyle, isDarkMode: isDarkMode })) : dataAvailable ? (_jsx(MetricsGraph, { data: series, from: from, to: to, profile: profile, setTimeRange: setTimeRange, onSampleClick: (timestamp, _value, labels, duration) => {
111
+ onPointClick(timestamp, labels, queryExpression, duration);
112
+ }, addLabelMatcher: addLabelMatcher, sampleUnit: sampleUnit, height: height, width: width, margin: margin })) : (_jsx(ProfileMetricsEmptyState, { message: "No data found. Try a different query." })) }, "metrics-graph-loaded") }));
124
113
  };
125
114
  export default ProfileMetricsGraph;
@@ -7,6 +7,7 @@ export interface QuerySelection {
7
7
  from: number;
8
8
  to: number;
9
9
  timeSelection: string;
10
+ sumBy?: string[];
10
11
  mergeFrom?: number;
11
12
  mergeTo?: number;
12
13
  }
@@ -20,6 +21,7 @@ interface ProfileSelectorProps {
20
21
  profileSelection: ProfileSelection | null;
21
22
  comparing: boolean;
22
23
  navigateTo: NavigateFunction;
24
+ suffix?: string;
23
25
  }
24
26
  export interface IProfileTypesResult {
25
27
  loading: boolean;
@@ -27,6 +29,6 @@ export interface IProfileTypesResult {
27
29
  error?: RpcError;
28
30
  }
29
31
  export declare const useProfileTypes: (client: QueryServiceClient) => IProfileTypesResult;
30
- declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, }: ProfileSelectorProps) => JSX.Element;
32
+ declare const ProfileSelector: ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, suffix, }: ProfileSelectorProps) => JSX.Element;
31
33
  export default ProfileSelector;
32
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;AAElD,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;AAO5D,MAAM,WAAW,cAAc;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,aAAa,EAAE,MAAM,CAAC;IACtB,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;CAC9B;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,OA2P7B,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,qJAWlB,oBAAoB,KAAG,GAAG,CAAC,OAsT7B,CAAC;AAEF,eAAe,eAAe,CAAC"}
@@ -11,15 +11,17 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
11
11
  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
- import { useEffect, useState } from 'react';
14
+ import { useEffect, useMemo, useState } from 'react';
15
+ import Select from 'react-select';
15
16
  import { Button, ButtonGroup, DateTimeRange, DateTimeRangePicker, IconButton, useGrpcMetadata, useParcaContext, } from '@parca/components';
16
17
  import { CloseIcon } from '@parca/icons';
17
18
  import { Query } from '@parca/parser';
18
19
  import { MergedProfileSelection } from '..';
19
- import MatchersInput from '../MatchersInput/index';
20
+ import MatchersInput, { useLabelNames } from '../MatchersInput/index';
20
21
  import { useMetricsGraphDimensions } from '../MetricsGraph/useMetricsGraphDimensions';
21
22
  import ProfileMetricsGraph, { ProfileMetricsEmptyState } from '../ProfileMetricsGraph';
22
23
  import ProfileTypeSelector from '../ProfileTypeSelector/index';
24
+ import { useSumBy } from '../useSumBy';
23
25
  import { useAutoQuerySelector } from './useAutoQuerySelector';
24
26
  export const useProfileTypes = (client) => {
25
27
  const [result, setResult] = useState(undefined);
@@ -38,12 +40,28 @@ export const useProfileTypes = (client) => {
38
40
  }, [client, metadata, loading]);
39
41
  return { loading, data: result, error };
40
42
  };
41
- const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, }) => {
43
+ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQuery, closeProfile, enforcedProfileName, profileSelection, comparing, navigateTo, suffix = '', }) => {
42
44
  const { loading: profileTypesLoading, data: profileTypesData, error, } = useProfileTypes(queryClient);
43
45
  const { heightStyle } = useMetricsGraphDimensions(comparing);
44
46
  const { viewComponent } = useParcaContext();
45
47
  const [timeRangeSelection, setTimeRangeSelection] = useState(DateTimeRange.fromRangeKey(querySelection.timeSelection, querySelection.from, querySelection.to));
46
48
  const [queryExpressionString, setQueryExpressionString] = useState(querySelection.expression);
49
+ const profileType = useMemo(() => {
50
+ return Query.parse(queryExpressionString).profileType();
51
+ }, [queryExpressionString]);
52
+ const { loading: labelNamesLoading, result } = useLabelNames(queryClient, profileType.toString());
53
+ const labels = useMemo(() => {
54
+ return result.response?.labelNames === undefined ? [] : result.response.labelNames;
55
+ }, [result]);
56
+ const [sumBy, setSumBy, userSelectedSumBy] = useSumBy(profileType, labelNamesLoading, result.response?.labelNames, {
57
+ urlParamKey: 'sum_by' + suffix,
58
+ });
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;
47
65
  useEffect(() => {
48
66
  if (enforcedProfileName !== '') {
49
67
  const [q, changed] = Query.parse(querySelection.expression).setProfileName(enforcedProfileName);
@@ -62,6 +80,9 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
62
80
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(queryExpressionString);
63
81
  const selectedProfileName = query.profileName();
64
82
  const setNewQueryExpression = (expr, updateTs = false) => {
83
+ if (!sumByLoading) {
84
+ setSumBy(sumBySelection);
85
+ }
65
86
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
66
87
  const delta = query.profileType().delta;
67
88
  const from = timeRangeSelection.getFromMs(updateTs);
@@ -136,20 +157,24 @@ const ProfileSelector = ({ queryClient, querySelection, selectProfile, selectQue
136
157
  profileTypesData,
137
158
  setProfileName,
138
159
  setQueryExpression,
139
- querySelection,
160
+ querySelection: { ...querySelection, sumBy },
140
161
  navigateTo,
141
162
  });
142
163
  const searchDisabled = queryExpressionString === undefined ||
143
164
  queryExpressionString === '' ||
144
165
  queryExpressionString === '{}';
145
166
  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) &&
146
- viewComponent !== undefined && _jsx("div", { children: viewComponent?.createViewComponent })] }), _jsx(MatchersInput, { queryClient: queryClient, setMatchersString: setMatchersString, runQuery: setQueryExpression, currentQuery: query, profileType: selectedProfileName })] }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsx(ButtonGroup, { children: _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
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));
169
+ }, placeholder: "Labels...", styles: {
170
+ indicatorSeparator: () => ({ display: 'none' }),
171
+ } })] }), _jsx(DateTimeRangePicker, { onRangeSelection: setTimeRangeSelection, range: timeRangeSelection }), _jsx(ButtonGroup, { children: _jsx(Button, { disabled: searchDisabled, onClick: (e) => {
147
172
  e.preventDefault();
148
173
  setQueryExpression(true);
149
174
  }, 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 &&
150
175
  querySelection.expression.length > 0 &&
151
176
  querySelection.from !== undefined &&
152
- 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, setTimeRange: (range) => {
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) => {
153
178
  const from = range.getFromMs();
154
179
  const to = range.getToMs();
155
180
  let mergedProfileParams = {};
@@ -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,IA0HV,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;CAC9B;AAED,eAAO,MAAM,oBAAoB,+GAO9B,KAAK,KAAG,IAkIV,CAAC"}
@@ -31,7 +31,9 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
31
31
  from: querySelection.from,
32
32
  to: querySelection.to,
33
33
  timeSelection: querySelection.timeSelection,
34
+ sumBy: querySelection.sumBy,
34
35
  };
36
+ const sumBy = queryA.sumBy?.join(',');
35
37
  let compareQuery = {
36
38
  compare_a: 'true',
37
39
  expression_a: encodeURIComponent(queryA.expression),
@@ -44,6 +46,10 @@ export const useAutoQuerySelector = ({ selectedProfileName, profileTypesData, se
44
46
  to_b: queryA.to.toString(),
45
47
  time_selection_b: queryA.timeSelection,
46
48
  };
49
+ if (sumBy != null) {
50
+ compareQuery.sum_by_a = sumBy;
51
+ compareQuery.sum_by_b = sumBy;
52
+ }
47
53
  if (profileA != null) {
48
54
  compareQuery = {
49
55
  ...SuffixParams(profileA.HistoryParams(), '_a'),
package/dist/styles.css CHANGED
@@ -1 +1 @@
1
- /*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-inset-2{bottom:-.5rem;left:-.5rem;right:-.5rem;top:-.5rem}.inset-y-0{bottom:0;top:0}.left-\[25px\]{left:25px}.left-0{left:0}.top-\[-46px\]{top:-46px}.right-0{right:0}.top-0{top:0}.top-\[-1px\]{top:-1px}.left-\[18px\]{left:18px}.bottom-0{bottom:0}.-top-3{top:-.75rem}.-right-3{right:-.75rem}.z-50{z-index:50}.z-10{z-index:10}.z-20{z-index:20}.m-auto{margin:auto}.m-2{margin:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.ml-2{margin-left:.5rem}.mb-2{margin-bottom:.5rem}.mb-0\.5{margin-bottom:.125rem}.mt-1\.5{margin-top:.375rem}.mb-0{margin-bottom:0}.mb-4{margin-bottom:1rem}.ml-3{margin-left:.75rem}.mr-6{margin-right:1.5rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.mr-4{margin-right:1rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-fit{height:-moz-fit-content;height:fit-content}.h-10{height:2.5rem}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-1{height:.25rem}.h-6{height:1.5rem}.h-4{height:1rem}.h-\[700px\]{height:700px}.h-\[80vh\]{height:80vh}.h-5{height:1.25rem}.h-14{height:3.5rem}.max-h-\[400px\]{max-height:400px}.max-h-\[300px\]{max-height:300px}.min-h-52{min-height:13rem}.min-h-\[38px\]{min-height:38px}.min-h-48{min-height:12rem}.min-h-\[78px\]{min-height:78px}.min-h-96{min-height:24rem}.min-h-\[700px\]{min-height:700px}.w-full{width:100%}.w-auto{width:auto}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-\[500px\]{width:500px}.w-max{width:-moz-max-content;width:max-content}.w-40{width:10rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-11{width:2.75rem}.w-\[52px\]{width:52px}.w-\[68px\]{width:68px}.w-\[76px\]{width:76px}.w-\[84px\]{width:84px}.w-\[92px\]{width:92px}.w-\[100px\]{width:100px}.w-\[108px\]{width:108px}.w-\[116px\]{width:116px}.w-4{width:1rem}.w-\[18px\]{width:18px}.w-8{width:2rem}.w-44{width:11rem}.w-\[460px\]{width:460px}.w-1\/5{width:20%}.w-11\/12{width:91.666667%}.w-1\/12{width:8.333333%}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.min-w-\[400px\]{min-width:400px}.min-w-60{min-width:15rem}.max-w-\[500px\]{max-width:500px}.max-w-\[300px\]{max-width:300px}.max-w-\[400px\]{max-width:400px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.origin-top-left{transform-origin:top left}.origin-bottom-left{transform-origin:bottom left}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.-rotate-90{--tw-rotate:-90deg}.-rotate-90,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-auto{cursor:auto}.cursor-grabbing{cursor:grabbing}.cursor-grab{cursor:grab}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-4{gap:1rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-clip{overflow:clip}.overflow-scroll{overflow:scroll}.overflow-x-hidden{overflow-x:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-full{border-radius:9999px}.rounded-none{border-radius:0}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.rounded-l{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.border{border-width:1px}.border-x{border-left-width:1px;border-right-width:1px}.border-y{border-bottom-width:1px;border-top-width:1px}.border-r{border-right-width:1px}.border-l{border-left-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-r-0{border-right-width:0}.border-l-0{border-left-width:0}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-r-gray-200{--tw-border-opacity:1;border-right-color:rgb(229 231 235/var(--tw-border-opacity))}.border-l-amber-900{--tw-border-opacity:1;border-left-color:rgb(120 53 15/var(--tw-border-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgb(243 244 246/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.stroke-gray-300{stroke:#d1d5db}.stroke-white{stroke:#fff}.stroke-\[3\]{stroke-width:3}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1\.5{padding:.375rem}.p-1{padding:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.\!py-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.\!px-3{padding-left:.75rem!important;padding-right:.75rem!important}.px-3{padding-left:.75rem;padding-right:.75rem}.py-0{padding-bottom:0;padding-top:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-8{padding-left:2rem;padding-right:2rem}.pr-0{padding-right:0}.pt-2{padding-top:.5rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pb-4{padding-bottom:1rem}.pb-2{padding-bottom:.5rem}.pb-6{padding-bottom:1.5rem}.pb-\[10px\]{padding-bottom:10px}.pl-1{padding-left:.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pl-5{padding-left:1.25rem}.pr-\[1\.7rem\]{padding-right:1.7rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-6{line-height:1.5rem}.leading-5{line-height:1.25rem}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-90{opacity:.9}.opacity-50{opacity:.5}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\]{--tw-shadow:0 0 10px 2px rgba(0,0,0,.3);--tw-shadow-colored:0 0 10px 2px var(--tw-shadow-color)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[stroke-dasharray\:6\2c 4\]{stroke-dasharray:6,4}.\[stroke-linecap\:round\]{stroke-linecap:round}.\[stroke-linejoin\:round\]{stroke-linejoin:round}.hover\:whitespace-normal:hover{white-space:normal}.hover\:bg-\[\#62626212\]:hover{background-color:#62626212}.hover\:bg-indigo-200:hover{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:flex{display:flex}[class~=theme-dark] .dark\:border{border-width:1px}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-r-gray-700{--tw-border-opacity:1;border-right-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-opacity-80{--tw-bg-opacity:0.8}[class~=theme-dark] .dark\:stroke-gray-500{stroke:#6b7280}[class~=theme-dark] .dark\:stroke-gray-700{stroke:#374151}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-indigo-500{--tw-text-opacity:1;color:rgb(99 102 241/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}[class~=theme-dark] .dark\:ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:ring-opacity-20{--tw-ring-opacity:0.2}[class~=theme-dark] .dark\:hover\:bg-\[\#ffffff12\]:hover{background-color:#ffffff12}[class~=theme-dark] .dark\:hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:hover\:bg-gray-700:hover{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .hover\:dark\:text-gray-100:hover{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:justify-end{justify-content:flex-end}}@media (min-width:1024px){.lg\:flex{display:flex}}
1
+ /*! tailwindcss v3.2.4 | MIT License | https://tailwindcss.com*/*,:after,:before{border:0 solid #e5e7eb;box-sizing:border-box}:after,:before{--tw-content:""}html{-webkit-text-size-adjust:100%;font-feature-settings:normal;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{line-height:inherit;margin:0}hr{border-top-width:1px;color:inherit;height:0}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}table{border-collapse:collapse;border-color:inherit;text-indent:0}button,input,optgroup,select,textarea{color:inherit;font-family:inherit;font-size:100%;font-weight:inherit;line-height:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:transparent;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:baseline}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{height:auto;max-width:100%}[hidden]{display:none}*,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }::backdrop{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.pointer-events-none{pointer-events:none}.visible{visibility:visible}.static{position:static}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.-inset-2{bottom:-.5rem;left:-.5rem;right:-.5rem;top:-.5rem}.inset-y-0{bottom:0;top:0}.left-\[25px\]{left:25px}.left-0{left:0}.top-\[-46px\]{top:-46px}.right-0{right:0}.top-0{top:0}.top-\[-1px\]{top:-1px}.left-\[18px\]{left:18px}.bottom-0{bottom:0}.z-50{z-index:50}.z-10{z-index:10}.z-20{z-index:20}.m-auto{margin:auto}.m-2{margin:.5rem}.mx-auto{margin-left:auto;margin-right:auto}.mx-2{margin-left:.5rem;margin-right:.5rem}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-20{margin-bottom:5rem;margin-top:5rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-4{margin-bottom:1rem;margin-top:1rem}.mr-3{margin-right:.75rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.ml-2{margin-left:.5rem}.mb-2{margin-bottom:.5rem}.mb-0\.5{margin-bottom:.125rem}.mt-1\.5{margin-top:.375rem}.mb-0{margin-bottom:0}.mb-4{margin-bottom:1rem}.ml-3{margin-left:.75rem}.mr-6{margin-right:1.5rem}.mr-1{margin-right:.25rem}.mb-1{margin-bottom:.25rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.block{display:block}.inline-block{display:inline-block}.flex{display:flex}.table{display:table}.grid{display:grid}.hidden{display:none}.h-fit{height:-moz-fit-content;height:fit-content}.h-10{height:2.5rem}.h-\[38px\]{height:38px}.h-auto{height:auto}.h-full{height:100%}.h-1{height:.25rem}.h-6{height:1.5rem}.h-4{height:1rem}.h-\[700px\]{height:700px}.h-\[80vh\]{height:80vh}.h-5{height:1.25rem}.max-h-\[400px\]{max-height:400px}.max-h-\[300px\]{max-height:300px}.min-h-52{min-height:13rem}.min-h-\[38px\]{min-height:38px}.min-h-48{min-height:12rem}.min-h-\[78px\]{min-height:78px}.min-h-96{min-height:24rem}.min-h-\[700px\]{min-height:700px}.w-full{width:100%}.w-auto{width:auto}.w-1\/4{width:25%}.w-3\/4{width:75%}.w-\[500px\]{width:500px}.w-max{width:-moz-max-content;width:max-content}.w-40{width:10rem}.w-80{width:20rem}.w-3{width:.75rem}.w-5{width:1.25rem}.w-7{width:1.75rem}.w-9{width:2.25rem}.w-11{width:2.75rem}.w-\[52px\]{width:52px}.w-\[68px\]{width:68px}.w-\[76px\]{width:76px}.w-\[84px\]{width:84px}.w-\[92px\]{width:92px}.w-\[100px\]{width:100px}.w-\[108px\]{width:108px}.w-\[116px\]{width:116px}.w-4{width:1rem}.w-\[18px\]{width:18px}.w-8{width:2rem}.w-44{width:11rem}.w-\[460px\]{width:460px}.w-1\/5{width:20%}.w-11\/12{width:91.666667%}.w-1\/12{width:8.333333%}.w-16{width:4rem}.w-fit{width:-moz-fit-content;width:fit-content}.w-\[420px\]{width:420px}.min-w-\[300px\]{min-width:300px}.min-w-\[400px\]{min-width:400px}.max-w-\[500px\]{max-width:500px}.max-w-\[300px\]{max-width:300px}.max-w-\[400px\]{max-width:400px}.max-w-md{max-width:28rem}.flex-1{flex:1 1 0%}.shrink-0{flex-shrink:0}.shrink{flex-shrink:1}.flex-grow-0{flex-grow:0}.flex-grow{flex-grow:1}.table-auto{table-layout:auto}.table-fixed{table-layout:fixed}.origin-top-left{transform-origin:top left}.origin-bottom-left{transform-origin:bottom left}.translate-y-1{--tw-translate-y:0.25rem}.translate-y-0,.translate-y-1{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.translate-y-0{--tw-translate-y:0px}.-rotate-90{--tw-rotate:-90deg}.-rotate-90,.transform{transform:translate(var(--tw-translate-x),var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.cursor-pointer{cursor:pointer}.cursor-default{cursor:default}.cursor-not-allowed{cursor:not-allowed}.cursor-auto{cursor:auto}.select-none{-webkit-user-select:none;-moz-user-select:none;user-select:none}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-start{align-content:flex-start}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.gap-4{gap:1rem}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-3{gap:.75rem}.gap-x-2{-moz-column-gap:.5rem;column-gap:.5rem}.space-y-5>:not([hidden])~:not([hidden]){--tw-space-y-reverse:0;margin-bottom:calc(1.25rem*var(--tw-space-y-reverse));margin-top:calc(1.25rem*(1 - var(--tw-space-y-reverse)))}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-clip{overflow:clip}.overflow-scroll{overflow:scroll}.overflow-x-hidden{overflow-x:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.break-all{word-break:break-all}.rounded{border-radius:.25rem}.rounded-lg{border-radius:.5rem}.rounded-md{border-radius:.375rem}.rounded-none{border-radius:0}.rounded-t-lg{border-top-left-radius:.5rem;border-top-right-radius:.5rem}.rounded-l{border-bottom-left-radius:.25rem;border-top-left-radius:.25rem}.rounded-r{border-bottom-right-radius:.25rem;border-top-right-radius:.25rem}.border{border-width:1px}.border-x{border-left-width:1px;border-right-width:1px}.border-y{border-bottom-width:1px;border-top-width:1px}.border-r{border-right-width:1px}.border-l{border-left-width:1px}.border-b{border-bottom-width:1px}.border-t{border-top-width:1px}.border-r-0{border-right-width:0}.border-l-0{border-left-width:0}.border-gray-300{--tw-border-opacity:1;border-color:rgb(209 213 219/var(--tw-border-opacity))}.border-red-400{--tw-border-opacity:1;border-color:rgb(248 113 113/var(--tw-border-opacity))}.border-gray-200{--tw-border-opacity:1;border-color:rgb(229 231 235/var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgb(156 163 175/var(--tw-border-opacity))}.border-r-gray-200{--tw-border-opacity:1;border-right-color:rgb(229 231 235/var(--tw-border-opacity))}.border-l-amber-900{--tw-border-opacity:1;border-left-color:rgb(120 53 15/var(--tw-border-opacity))}.bg-gray-50{--tw-bg-opacity:1;background-color:rgb(249 250 251/var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgb(229 231 235/var(--tw-bg-opacity))}.bg-indigo-600{--tw-bg-opacity:1;background-color:rgb(79 70 229/var(--tw-bg-opacity))}.bg-white{--tw-bg-opacity:1;background-color:rgb(255 255 255/var(--tw-bg-opacity))}.bg-red-100{--tw-bg-opacity:1;background-color:rgb(254 226 226/var(--tw-bg-opacity))}.bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}.bg-yellow-200{--tw-bg-opacity:1;background-color:rgb(254 240 138/var(--tw-bg-opacity))}.bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}.bg-indigo-100{--tw-bg-opacity:1;background-color:rgb(224 231 255/var(--tw-bg-opacity))}.bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}.bg-indigo-50{--tw-bg-opacity:1;background-color:rgb(238 242 255/var(--tw-bg-opacity))}.bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}.bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}.bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}.bg-inherit{background-color:inherit}.bg-opacity-90{--tw-bg-opacity:0.9}.fill-transparent{fill:transparent}.fill-current{fill:currentColor}.stroke-gray-300{stroke:#d1d5db}.stroke-white{stroke:#fff}.stroke-\[3\]{stroke-width:3}.p-2{padding:.5rem}.p-3{padding:.75rem}.p-10{padding:2.5rem}.p-4{padding:1rem}.p-1\.5{padding:.375rem}.p-1{padding:.25rem}.px-2{padding-left:.5rem;padding-right:.5rem}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.py-4{padding-bottom:1rem;padding-top:1rem}.px-4{padding-left:1rem;padding-right:1rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.\!py-2{padding-bottom:.5rem!important;padding-top:.5rem!important}.\!px-3{padding-left:.75rem!important;padding-right:.75rem!important}.px-3{padding-left:.75rem;padding-right:.75rem}.py-0{padding-bottom:0;padding-top:0}.px-1{padding-left:.25rem;padding-right:.25rem}.px-8{padding-left:2rem;padding-right:2rem}.pr-0{padding-right:0}.pt-2{padding-top:.5rem}.pl-3{padding-left:.75rem}.pr-9{padding-right:2.25rem}.pb-4{padding-bottom:1rem}.pb-2{padding-bottom:.5rem}.pb-6{padding-bottom:1.5rem}.pb-\[10px\]{padding-bottom:10px}.pl-1{padding-left:.25rem}.pr-10{padding-right:2.5rem}.pr-2{padding-right:.5rem}.pl-5{padding-left:1.25rem}.pr-\[1\.7rem\]{padding-right:1.7rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-top{vertical-align:top}.font-mono{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xs{font-size:.75rem;line-height:1rem}.text-base{font-size:1rem;line-height:1.5rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.text-\[10px\]{font-size:10px}.text-lg{font-size:1.125rem;line-height:1.75rem}.font-semibold{font-weight:600}.font-bold{font-weight:700}.font-medium{font-weight:500}.font-normal{font-weight:400}.uppercase{text-transform:uppercase}.capitalize{text-transform:capitalize}.leading-6{line-height:1.5rem}.leading-5{line-height:1.25rem}.text-gray-700{--tw-text-opacity:1;color:rgb(55 65 81/var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgb(107 114 128/var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}.text-red-700{--tw-text-opacity:1;color:rgb(185 28 28/var(--tw-text-opacity))}.text-black{--tw-text-opacity:1;color:rgb(0 0 0/var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}.text-indigo-600{--tw-text-opacity:1;color:rgb(79 70 229/var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgb(17 24 39/var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgb(75 85 99/var(--tw-text-opacity))}.\!text-indigo-600{--tw-text-opacity:1!important;color:rgb(79 70 229/var(--tw-text-opacity))!important}.opacity-100{opacity:1}.opacity-0{opacity:0}.opacity-90{opacity:.9}.opacity-50{opacity:.5}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\]{--tw-shadow:0 0 10px 2px rgba(0,0,0,.3);--tw-shadow-colored:0 0 10px 2px var(--tw-shadow-color)}.shadow-\[0_0_10px_2px_rgba\(0\2c 0\2c 0\2c 0\.3\)\],.shadow-lg{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,.1),0 4px 6px -4px rgba(0,0,0,.1);--tw-shadow-colored:0 10px 15px -3px var(--tw-shadow-color),0 4px 6px -4px var(--tw-shadow-color)}.shadow-sm{--tw-shadow:0 1px 2px 0 rgba(0,0,0,.05);--tw-shadow-colored:0 1px 2px 0 var(--tw-shadow-color)}.shadow,.shadow-sm{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,.1),0 1px 2px -1px rgba(0,0,0,.1);--tw-shadow-colored:0 1px 3px 0 var(--tw-shadow-color),0 1px 2px -1px var(--tw-shadow-color)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,.1),0 2px 4px -2px rgba(0,0,0,.1);--tw-shadow-colored:0 4px 6px -1px var(--tw-shadow-color),0 2px 4px -2px var(--tw-shadow-color);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.ring-1{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.ring-black{--tw-ring-opacity:1;--tw-ring-color:rgb(0 0 0/var(--tw-ring-opacity))}.ring-opacity-5{--tw-ring-opacity:0.05}.blur{--tw-blur:blur(8px)}.blur,.invert{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.invert{--tw-invert:invert(100%)}.filter{filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.transition{transition-duration:.15s;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.duration-150{transition-duration:.15s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.\[stroke-dasharray\:6\2c 4\]{stroke-dasharray:6,4}.\[stroke-linecap\:round\]{stroke-linecap:round}.\[stroke-linejoin\:round\]{stroke-linejoin:round}.hover\:whitespace-normal:hover{white-space:normal}.hover\:bg-\[\#62626212\]:hover{background-color:#62626212}.hover\:bg-indigo-200:hover{--tw-bg-opacity:1;background-color:rgb(199 210 254/var(--tw-bg-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgb(99 102 241/var(--tw-border-opacity))}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}.focus\:ring-1:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(1px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-1:focus,.focus\:ring-2:focus{box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}.focus\:ring-2:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(2px + var(--tw-ring-offset-width)) var(--tw-ring-color)}.focus\:ring-indigo-500:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(99 102 241/var(--tw-ring-opacity))}.focus\:ring-indigo-600:focus{--tw-ring-opacity:1;--tw-ring-color:rgb(79 70 229/var(--tw-ring-opacity))}.focus\:ring-offset-2:focus{--tw-ring-offset-width:2px}.group:hover .group-hover\:flex{display:flex}[class~=theme-dark] .dark\:border{border-width:1px}[class~=theme-dark] .dark\:border-gray-500{--tw-border-opacity:1;border-color:rgb(107 114 128/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-600{--tw-border-opacity:1;border-color:rgb(75 85 99/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-gray-700{--tw-border-opacity:1;border-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:border-r-gray-700{--tw-border-opacity:1;border-right-color:rgb(55 65 81/var(--tw-border-opacity))}[class~=theme-dark] .dark\:bg-gray-900{--tw-bg-opacity:1;background-color:rgb(17 24 39/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-800{--tw-bg-opacity:1;background-color:rgb(31 41 55/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-700{--tw-bg-opacity:1;background-color:rgb(55 65 81/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-500{--tw-bg-opacity:1;background-color:rgb(107 114 128/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-yellow-700{--tw-bg-opacity:1;background-color:rgb(161 98 7/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-gray-600{--tw-bg-opacity:1;background-color:rgb(75 85 99/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-indigo-500{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-black{--tw-bg-opacity:1;background-color:rgb(0 0 0/var(--tw-bg-opacity))}[class~=theme-dark] .dark\:bg-opacity-80{--tw-bg-opacity:0.8}[class~=theme-dark] .dark\:stroke-gray-500{stroke:#6b7280}[class~=theme-dark] .dark\:stroke-gray-700{stroke:#374151}[class~=theme-dark] .dark\:text-gray-300{--tw-text-opacity:1;color:rgb(209 213 219/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-400{--tw-text-opacity:1;color:rgb(156 163 175/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-white{--tw-text-opacity:1;color:rgb(255 255 255/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-200{--tw-text-opacity:1;color:rgb(229 231 235/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-gray-50{--tw-text-opacity:1;color:rgb(249 250 251/var(--tw-text-opacity))}[class~=theme-dark] .dark\:text-indigo-500{--tw-text-opacity:1;color:rgb(99 102 241/var(--tw-text-opacity))}[class~=theme-dark] .dark\:\!text-indigo-400{--tw-text-opacity:1!important;color:rgb(129 140 248/var(--tw-text-opacity))!important}[class~=theme-dark] .dark\:ring-white{--tw-ring-opacity:1;--tw-ring-color:rgb(255 255 255/var(--tw-ring-opacity))}[class~=theme-dark] .dark\:ring-opacity-20{--tw-ring-opacity:0.2}[class~=theme-dark] .dark\:hover\:bg-\[\#ffffff12\]:hover{background-color:#ffffff12}[class~=theme-dark] .dark\:hover\:bg-indigo-500:hover{--tw-bg-opacity:1;background-color:rgb(99 102 241/var(--tw-bg-opacity))}[class~=theme-dark] .hover\:dark\:text-gray-100:hover{--tw-text-opacity:1;color:rgb(243 244 246/var(--tw-text-opacity))}@media (min-width:640px){.sm\:inline{display:inline}.sm\:text-sm{font-size:.875rem;line-height:1.25rem}}@media (min-width:768px){.md\:block{display:block}.md\:flex-row{flex-direction:row}.md\:items-end{align-items:flex-end}.md\:justify-end{justify-content:flex-end}}@media (min-width:1024px){.lg\:flex{display:flex}}
@@ -0,0 +1,8 @@
1
+ import { ProfileType } from '@parca/parser';
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;
6
+ defaultValue?: string[];
7
+ }) => [string[], (labels: string[]) => void, string[] | undefined];
8
+ //# sourceMappingURL=useSumBy.d.ts.map
@@ -0,0 +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"}
@@ -10,16 +10,13 @@
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, useRef, useState } from 'react';
13
+ import { useCallback, useEffect, useMemo, useState } from 'react';
14
14
  import { useParcaContext, useURLState } from '@parca/components';
15
15
  export const DEFAULT_EMPTY_SUM_BY = [];
16
16
  const getDefaultSumBy = (profile, labels) => {
17
17
  if (profile === undefined || labels === undefined) {
18
18
  return undefined;
19
19
  }
20
- if (!profile.delta) {
21
- return [];
22
- }
23
20
  if (labels.includes('comm')) {
24
21
  return ['comm'];
25
22
  }
@@ -31,13 +28,13 @@ const getDefaultSumBy = (profile, labels) => {
31
28
  }
32
29
  return undefined;
33
30
  };
34
- export const useSumBy = (profileType, labels) => {
31
+ export const useSumBy = (profileType, labelNamesLoading, labels, { urlParamKey = 'sum_by', withURLUpdate = true, defaultValue, } = {}) => {
35
32
  const { navigateTo } = useParcaContext();
36
33
  const [userSelectedSumByParam, setUserSelectedSumByParam] = useURLState({
37
- param: 'sum_by',
34
+ param: urlParamKey,
38
35
  navigateTo,
36
+ withURLUpdate,
39
37
  });
40
- const previousProfileType = useRef(profileType);
41
38
  const userSelectedSumBy = useMemo(() => {
42
39
  if (userSelectedSumByParam?.length === 0) {
43
40
  return undefined;
@@ -45,10 +42,14 @@ export const useSumBy = (profileType, labels) => {
45
42
  if (userSelectedSumByParam === '__none__') {
46
43
  return [];
47
44
  }
45
+ if (userSelectedSumByParam === undefined && defaultValue !== undefined) {
46
+ return defaultValue;
47
+ }
48
48
  if (typeof userSelectedSumByParam === 'string') {
49
49
  return [userSelectedSumByParam];
50
50
  }
51
51
  return userSelectedSumByParam;
52
+ // eslint-disable-next-line react-hooks/exhaustive-deps
52
53
  }, [userSelectedSumByParam]);
53
54
  const setUserSelectedSumBy = useCallback((sumBy) => {
54
55
  if (sumBy.length === 0) {
@@ -64,17 +65,14 @@ export const useSumBy = (profileType, labels) => {
64
65
  }, [setUserSelectedSumByParam]);
65
66
  const [defaultSumBy, setDefaultSumBy] = useState(getDefaultSumBy(profileType, labels));
66
67
  useEffect(() => {
67
- setDefaultSumBy(getDefaultSumBy(profileType, labels));
68
- }, [profileType, labels]);
69
- useEffect(() => {
70
- if (profileType === undefined ||
71
- profileType.toString() === previousProfileType.current?.toString()) {
68
+ if (labelNamesLoading) {
72
69
  return;
73
70
  }
74
- // Reset user selected sumBy if profile type changes
75
- setUserSelectedSumBy(['']);
76
- previousProfileType.current = profileType;
77
- // eslint-disable-next-line react-hooks/exhaustive-deps
78
- }, [profileType]);
79
- return [userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY, setUserSelectedSumBy];
71
+ setDefaultSumBy(getDefaultSumBy(profileType, labels));
72
+ }, [profileType, labels, labelNamesLoading]);
73
+ let sumBy = userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
74
+ if (profileType?.delta !== true) {
75
+ sumBy = [];
76
+ }
77
+ return [sumBy, setUserSelectedSumBy, userSelectedSumBy];
80
78
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.411",
3
+ "version": "0.16.413",
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": "8885ee532a664069e946e488f60b24cdac9c80f0"
76
+ "gitHead": "8b3121b9f7c20b041cf55ca866260acbe0bd70c2"
77
77
  }
@@ -73,6 +73,7 @@ const ProfileExplorerCompare = ({
73
73
  enforcedProfileName={''}
74
74
  comparing={true}
75
75
  navigateTo={navigateTo}
76
+ suffix="_a"
76
77
  />
77
78
  </Card>
78
79
  <Card className="mt-2 p-2">
@@ -86,6 +87,7 @@ const ProfileExplorerCompare = ({
86
87
  enforcedProfileName={Query.parse(queryA.expression).profileName()}
87
88
  comparing={true}
88
89
  navigateTo={navigateTo}
90
+ suffix="_b"
89
91
  />
90
92
  </Card>
91
93
  </div>
@@ -48,6 +48,7 @@ const ProfileExplorerSingle = ({
48
48
  comparing={false}
49
49
  enforcedProfileName={''} // TODO
50
50
  navigateTo={navigateTo}
51
+ suffix="_a"
51
52
  />
52
53
  </Card>
53
54
  {profile != null ? (
@@ -120,12 +120,14 @@ const ProfileExplorerApp = ({
120
120
  merge_to_a,
121
121
  time_selection_a,
122
122
  compare_a,
123
+ sum_by_a,
123
124
  from_b,
124
125
  to_b,
125
126
  merge_from_b,
126
127
  merge_to_b,
127
128
  time_selection_b,
128
129
  compare_b,
130
+ sum_by_b,
129
131
  filter_by_function,
130
132
  dashboard_items,
131
133
  } = queryParams;
@@ -223,6 +225,7 @@ const ProfileExplorerApp = ({
223
225
  from: parseInt(from_a as string),
224
226
  to: parseInt(to_a as string),
225
227
  timeSelection: time_selection_a as string,
228
+ sumBy: sum_by_a as string[],
226
229
  };
227
230
 
228
231
  // Show the SingleProfileExplorer when not comparing
@@ -280,6 +283,7 @@ const ProfileExplorerApp = ({
280
283
  from: parseInt(from_b as string),
281
284
  to: parseInt(to_b as string),
282
285
  timeSelection: time_selection_b as string,
286
+ sumBy: sum_by_b as string[],
283
287
  };
284
288
 
285
289
  const selectQueryA = (q: QuerySelection): void => {
@@ -28,12 +28,9 @@ import {Query} from '@parca/parser';
28
28
  import {capitalizeOnlyFirstLetter, getStepDuration} from '@parca/utilities';
29
29
 
30
30
  import {MergedProfileSelection, ProfileSelection} from '..';
31
- import {useLabelNames} from '../MatchersInput';
32
31
  import MetricsGraph from '../MetricsGraph';
33
32
  import {useMetricsGraphDimensions} from '../MetricsGraph/useMetricsGraphDimensions';
34
33
  import useGrpcQuery from '../useGrpcQuery';
35
- import {Toolbar} from './Toolbar';
36
- import {DEFAULT_EMPTY_SUM_BY, useSumBy} from './useSumBy';
37
34
 
38
35
  interface ProfileMetricsEmptyStateProps {
39
36
  message: string;
@@ -61,9 +58,12 @@ export const ProfileMetricsEmptyState = ({message}: ProfileMetricsEmptyStateProp
61
58
  interface ProfileMetricsGraphProps {
62
59
  queryClient: QueryServiceClient;
63
60
  queryExpression: string;
61
+ dirtyQueryExpression: string;
64
62
  profile: ProfileSelection | null;
65
63
  from: number;
66
64
  to: number;
65
+ sumByLoading: boolean;
66
+ sumBy: string[];
67
67
  setTimeRange: (range: DateTimeRange) => void;
68
68
  addLabelMatcher: (
69
69
  labels: {key: string; value: string} | Array<{key: string; value: string}>
@@ -98,7 +98,7 @@ export const useQueryRange = (
98
98
  queryExpression: string,
99
99
  start: number,
100
100
  end: number,
101
- sumBy: string[] = DEFAULT_EMPTY_SUM_BY,
101
+ sumBy: string[],
102
102
  skip = false
103
103
  ): IQueryRangeState => {
104
104
  const metadata = useGrpcMetadata();
@@ -141,7 +141,7 @@ export const useQueryRange = (
141
141
  },
142
142
  options: {
143
143
  retry: false,
144
- enabled: !skip && sumBy !== DEFAULT_EMPTY_SUM_BY,
144
+ enabled: !skip,
145
145
  staleTime: 1000 * 60 * 5, // 5 minutes
146
146
  },
147
147
  });
@@ -159,24 +159,14 @@ const ProfileMetricsGraph = ({
159
159
  addLabelMatcher,
160
160
  onPointClick,
161
161
  comparing = false,
162
+ sumBy,
163
+ sumByLoading,
162
164
  }: ProfileMetricsGraphProps): JSX.Element => {
163
- const profileType = useMemo(() => {
164
- return Query.parse(queryExpression).profileType();
165
- }, [queryExpression]);
166
-
167
- const {loading: labelNamesLoading, result: labelNamesResult} = useLabelNames(
168
- queryClient,
169
- profileType.toString() ?? '',
170
- from,
171
- to
172
- );
173
- const [sumBy, setSumBy] = useSumBy(profileType, labelNamesResult.response?.labelNames);
174
-
175
165
  const {
176
166
  isLoading: metricsGraphLoading,
177
167
  response,
178
168
  error,
179
- } = useQueryRange(queryClient, queryExpression, from, to, sumBy, labelNamesLoading);
169
+ } = useQueryRange(queryClient, queryExpression, from, to, sumBy, sumByLoading);
180
170
  const {onError, perf, authenticationErrorMessage, isDarkMode} = useParcaContext();
181
171
  const {width, height, margin, heightStyle} = useMetricsGraphDimensions(comparing);
182
172
 
@@ -197,13 +187,7 @@ const ProfileMetricsGraph = ({
197
187
  const series = response?.series;
198
188
  const dataAvailable = series !== null && series !== undefined && series?.length > 0;
199
189
 
200
- const loading = metricsGraphLoading || labelNamesLoading;
201
-
202
- if (!labelNamesLoading && labelNamesResult?.error?.message != null) {
203
- return (
204
- <ErrorContent errorMessage={capitalizeOnlyFirstLetter(labelNamesResult.error.message)} />
205
- );
206
- }
190
+ const loading = metricsGraphLoading;
207
191
 
208
192
  if (!metricsGraphLoading && error !== null) {
209
193
  if (authenticationErrorMessage !== undefined && error.code === 'UNAUTHENTICATED') {
@@ -233,11 +217,6 @@ const ProfileMetricsGraph = ({
233
217
  animate={{display: 'block', opacity: 1}}
234
218
  transition={{duration: 0.5}}
235
219
  >
236
- <Toolbar
237
- sumBy={sumBy}
238
- setSumBy={setSumBy}
239
- labels={labelNamesResult.response?.labelNames ?? []}
240
- />
241
220
  {loading ? (
242
221
  <MetricsGraphSkeleton heightStyle={heightStyle} isDarkMode={isDarkMode} />
243
222
  ) : dataAvailable ? (
@@ -11,9 +11,10 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
 
14
- import React, {useEffect, useState} from 'react';
14
+ import React, {useEffect, useMemo, useState} from 'react';
15
15
 
16
16
  import {RpcError} from '@protobuf-ts/runtime-rpc';
17
+ import Select from 'react-select';
17
18
 
18
19
  import {Label, ProfileTypesResponse, QueryServiceClient} from '@parca/client';
19
20
  import {
@@ -30,10 +31,11 @@ import {Query} from '@parca/parser';
30
31
  import {type NavigateFunction} from '@parca/utilities';
31
32
 
32
33
  import {MergedProfileSelection, ProfileSelection} from '..';
33
- import MatchersInput from '../MatchersInput/index';
34
+ import MatchersInput, {useLabelNames} from '../MatchersInput/index';
34
35
  import {useMetricsGraphDimensions} from '../MetricsGraph/useMetricsGraphDimensions';
35
36
  import ProfileMetricsGraph, {ProfileMetricsEmptyState} from '../ProfileMetricsGraph';
36
37
  import ProfileTypeSelector from '../ProfileTypeSelector/index';
38
+ import {useSumBy} from '../useSumBy';
37
39
  import {useAutoQuerySelector} from './useAutoQuerySelector';
38
40
 
39
41
  export interface QuerySelection {
@@ -41,6 +43,7 @@ export interface QuerySelection {
41
43
  from: number;
42
44
  to: number;
43
45
  timeSelection: string;
46
+ sumBy?: string[];
44
47
  mergeFrom?: number;
45
48
  mergeTo?: number;
46
49
  }
@@ -55,6 +58,7 @@ interface ProfileSelectorProps {
55
58
  profileSelection: ProfileSelection | null;
56
59
  comparing: boolean;
57
60
  navigateTo: NavigateFunction;
61
+ suffix?: string;
58
62
  }
59
63
 
60
64
  export interface IProfileTypesResult {
@@ -93,6 +97,7 @@ const ProfileSelector = ({
93
97
  profileSelection,
94
98
  comparing,
95
99
  navigateTo,
100
+ suffix = '',
96
101
  }: ProfileSelectorProps): JSX.Element => {
97
102
  const {
98
103
  loading: profileTypesLoading,
@@ -108,6 +113,38 @@ const ProfileSelector = ({
108
113
 
109
114
  const [queryExpressionString, setQueryExpressionString] = useState(querySelection.expression);
110
115
 
116
+ const profileType = useMemo(() => {
117
+ return Query.parse(queryExpressionString).profileType();
118
+ }, [queryExpressionString]);
119
+
120
+ const {loading: labelNamesLoading, result} = useLabelNames(queryClient, profileType.toString());
121
+
122
+ const labels = useMemo(() => {
123
+ return result.response?.labelNames === undefined ? [] : result.response.labelNames;
124
+ }, [result]);
125
+
126
+ const [sumBy, setSumBy, userSelectedSumBy] = useSumBy(
127
+ profileType,
128
+ labelNamesLoading,
129
+ result.response?.labelNames,
130
+ {
131
+ urlParamKey: 'sum_by' + suffix,
132
+ }
133
+ );
134
+
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
+ );
145
+
146
+ const sumByLoading = labelNamesLoading;
147
+
111
148
  useEffect(() => {
112
149
  if (enforcedProfileName !== '') {
113
150
  const [q, changed] = Query.parse(querySelection.expression).setProfileName(
@@ -132,6 +169,9 @@ const ProfileSelector = ({
132
169
  const selectedProfileName = query.profileName();
133
170
 
134
171
  const setNewQueryExpression = (expr: string, updateTs = false): void => {
172
+ if (!sumByLoading) {
173
+ setSumBy(sumBySelection);
174
+ }
135
175
  const query = enforcedProfileName !== '' ? enforcedProfileNameQuery() : Query.parse(expr);
136
176
  const delta = query.profileType().delta;
137
177
  const from = timeRangeSelection.getFromMs(updateTs);
@@ -217,7 +257,7 @@ const ProfileSelector = ({
217
257
  profileTypesData,
218
258
  setProfileName,
219
259
  setQueryExpression,
220
- querySelection,
260
+ querySelection: {...querySelection, sumBy},
221
261
  navigateTo,
222
262
  });
223
263
 
@@ -255,6 +295,27 @@ const ProfileSelector = ({
255
295
  profileType={selectedProfileName}
256
296
  />
257
297
  </div>
298
+ <div className="pb-6">
299
+ <div className="mb-0.5 mt-1.5 flex items-center justify-between">
300
+ <label className="text-xs">Sum by</label>
301
+ </div>
302
+ <Select
303
+ defaultValue={[]}
304
+ isMulti
305
+ name="colors"
306
+ options={labels.map(label => ({label, value: label}))}
307
+ className="parca-select-container text-sm w-80"
308
+ classNamePrefix="parca-select"
309
+ value={sumBySelection.map(sumBy => ({label: sumBy, value: sumBy}))}
310
+ onChange={selectedOptions => {
311
+ setSumBySelection(selectedOptions.map(option => option.value));
312
+ }}
313
+ placeholder="Labels..."
314
+ styles={{
315
+ indicatorSeparator: () => ({display: 'none'}),
316
+ }}
317
+ />
318
+ </div>
258
319
  <DateTimeRangePicker
259
320
  onRangeSelection={setTimeRangeSelection}
260
321
  range={timeRangeSelection}
@@ -284,10 +345,13 @@ const ProfileSelector = ({
284
345
  <ProfileMetricsGraph
285
346
  queryClient={queryClient}
286
347
  queryExpression={querySelection.expression}
348
+ dirtyQueryExpression={queryExpressionString}
287
349
  from={querySelection.from}
288
350
  to={querySelection.to}
289
351
  profile={profileSelection}
290
352
  comparing={comparing}
353
+ sumBy={sumBy}
354
+ sumByLoading={sumByLoading}
291
355
  setTimeRange={(range: DateTimeRange) => {
292
356
  const from = range.getFromMs();
293
357
  const to = range.getToMs();
@@ -61,9 +61,12 @@ export const useAutoQuerySelector = ({
61
61
  from: querySelection.from,
62
62
  to: querySelection.to,
63
63
  timeSelection: querySelection.timeSelection,
64
+ sumBy: querySelection.sumBy,
64
65
  };
65
66
 
66
- let compareQuery = {
67
+ const sumBy = queryA.sumBy?.join(',');
68
+
69
+ let compareQuery: Record<string, string> = {
67
70
  compare_a: 'true',
68
71
  expression_a: encodeURIComponent(queryA.expression),
69
72
  from_a: queryA.from.toString(),
@@ -77,6 +80,11 @@ export const useAutoQuerySelector = ({
77
80
  time_selection_b: queryA.timeSelection,
78
81
  };
79
82
 
83
+ if (sumBy != null) {
84
+ compareQuery.sum_by_a = sumBy;
85
+ compareQuery.sum_by_b = sumBy;
86
+ }
87
+
80
88
  if (profileA != null) {
81
89
  compareQuery = {
82
90
  ...SuffixParams(profileA.HistoryParams(), '_a'),
@@ -11,7 +11,7 @@
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, useRef, useState} from 'react';
14
+ import {useCallback, useEffect, useMemo, useState} from 'react';
15
15
 
16
16
  import {useParcaContext, useURLState} from '@parca/components';
17
17
  import {ProfileType} from '@parca/parser';
@@ -26,10 +26,6 @@ const getDefaultSumBy = (
26
26
  return undefined;
27
27
  }
28
28
 
29
- if (!profile.delta) {
30
- return [];
31
- }
32
-
33
29
  if (labels.includes('comm')) {
34
30
  return ['comm'];
35
31
  }
@@ -47,14 +43,24 @@ const getDefaultSumBy = (
47
43
 
48
44
  export const useSumBy = (
49
45
  profileType: ProfileType | undefined,
50
- labels: string[] | undefined
51
- ): [string[], (labels: string[]) => void] => {
46
+ labelNamesLoading: boolean,
47
+ labels: string[] | undefined,
48
+ {
49
+ urlParamKey = 'sum_by',
50
+ withURLUpdate = true,
51
+ defaultValue,
52
+ }: {
53
+ urlParamKey?: string;
54
+ withURLUpdate?: boolean;
55
+ defaultValue?: string[];
56
+ } = {}
57
+ ): [string[], (labels: string[]) => void, string[] | undefined] => {
52
58
  const {navigateTo} = useParcaContext();
53
59
  const [userSelectedSumByParam, setUserSelectedSumByParam] = useURLState({
54
- param: 'sum_by',
60
+ param: urlParamKey,
55
61
  navigateTo,
62
+ withURLUpdate,
56
63
  });
57
- const previousProfileType = useRef<ProfileType | undefined>(profileType);
58
64
 
59
65
  const userSelectedSumBy = useMemo<string[] | undefined>(() => {
60
66
  if (userSelectedSumByParam?.length === 0) {
@@ -65,11 +71,17 @@ export const useSumBy = (
65
71
  return [];
66
72
  }
67
73
 
74
+ if (userSelectedSumByParam === undefined && defaultValue !== undefined) {
75
+ return defaultValue;
76
+ }
77
+
68
78
  if (typeof userSelectedSumByParam === 'string') {
69
79
  return [userSelectedSumByParam];
70
80
  }
71
81
 
72
82
  return userSelectedSumByParam;
83
+
84
+ // eslint-disable-next-line react-hooks/exhaustive-deps
73
85
  }, [userSelectedSumByParam]);
74
86
 
75
87
  const setUserSelectedSumBy = useCallback(
@@ -95,23 +107,17 @@ export const useSumBy = (
95
107
  );
96
108
 
97
109
  useEffect(() => {
98
- setDefaultSumBy(getDefaultSumBy(profileType, labels));
99
- }, [profileType, labels]);
100
-
101
- useEffect(() => {
102
- if (
103
- profileType === undefined ||
104
- profileType.toString() === previousProfileType.current?.toString()
105
- ) {
110
+ if (labelNamesLoading) {
106
111
  return;
107
112
  }
113
+ setDefaultSumBy(getDefaultSumBy(profileType, labels));
114
+ }, [profileType, labels, labelNamesLoading]);
108
115
 
109
- // Reset user selected sumBy if profile type changes
110
- setUserSelectedSumBy(['']);
111
- previousProfileType.current = profileType;
116
+ let sumBy = userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY;
112
117
 
113
- // eslint-disable-next-line react-hooks/exhaustive-deps
114
- }, [profileType]);
118
+ if (profileType?.delta !== true) {
119
+ sumBy = [];
120
+ }
115
121
 
116
- return [userSelectedSumBy ?? defaultSumBy ?? DEFAULT_EMPTY_SUM_BY, setUserSelectedSumBy];
122
+ return [sumBy, setUserSelectedSumBy, userSelectedSumBy];
117
123
  };
@@ -1,9 +0,0 @@
1
- import { ReactNode } from 'react';
2
- interface Props {
3
- sumBy: string[];
4
- setSumBy: (sumBy: string[]) => void;
5
- labels: string[];
6
- }
7
- export declare const Toolbar: ({ sumBy, setSumBy, labels }: Props) => ReactNode;
8
- export {};
9
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/ProfileMetricsGraph/Toolbar/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,SAAS,EAA2B,MAAM,OAAO,CAAC;AAQ1D,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACpC,MAAM,EAAE,MAAM,EAAE,CAAC;CAClB;AAED,eAAO,MAAM,OAAO,gCAA+B,KAAK,KAAG,SAkE1D,CAAC"}
@@ -1,29 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- // Copyright 2022 The Parca Authors
3
- // Licensed under the Apache License, Version 2.0 (the "License");
4
- // you may not use this file except in compliance with the License.
5
- // You may obtain a copy of the License at
6
- //
7
- // http://www.apache.org/licenses/LICENSE-2.0
8
- //
9
- // Unless required by applicable law or agreed to in writing, software
10
- // distributed under the License is distributed on an "AS IS" BASIS,
11
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
- // See the License for the specific language governing permissions and
13
- // limitations under the License.
14
- import { useId, useMemo, useState } from 'react';
15
- import { Icon } from '@iconify/react';
16
- import Draggable from 'react-draggable';
17
- import Select from 'react-select';
18
- import { IconButton } from '@parca/components';
19
- export const Toolbar = ({ sumBy, setSumBy, labels }) => {
20
- const [collapsed, setCollapsed] = useState(false);
21
- const [isDragging, setIsDragging] = useState(false);
22
- const idWithColon = useId();
23
- const id = useMemo(() => idWithColon.replace(/[^a-zA-Z0-9]/g, ''), [idWithColon]);
24
- return (_jsx(Draggable, { handle: `#${id}`, onStart: () => setIsDragging(true), onStop: () => setIsDragging(false), bounds: "parent", defaultPosition: { x: 96, y: 4 }, children: _jsx("div", { className: "absolute rounded-full bg-gray-100 dark:bg-gray-800 z-10 text-xs", children: _jsxs("div", { className: "flex items-center h-14 gap-4 py-1 px-3", children: [_jsx(Icon, { icon: "radix-icons:drag-handle-dots-2", height: 20, className: isDragging ? 'cursor-grabbing' : 'cursor-grab', id: id }), !collapsed ? (_jsxs("div", { className: "flex gap-2 items-center mr-4", children: [_jsx("span", { children: "Sum by" }), _jsx(Select, { defaultValue: [], isMulti: true, name: "colors", options: labels.map(label => ({ label, value: label })), className: "parca-select-container min-w-60", classNamePrefix: "parca-select", value: sumBy.map(sumBy => ({ label: sumBy, value: sumBy })), onChange: selectedOptions => {
25
- setSumBy(selectedOptions.map(option => option.value));
26
- }, placeholder: "Labels...", styles: {
27
- indicatorSeparator: () => ({ display: 'none' }),
28
- } })] })) : null, _jsxs("div", { className: "relative", children: [_jsx(IconButton, { icon: _jsx(Icon, { icon: collapsed ? 'iconamoon:arrow-right-2-light' : 'iconamoon:arrow-left-2-light', height: 24 }), onClick: () => setCollapsed(!collapsed), className: "hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full p-1" }), collapsed && sumBy.length > 0 ? (_jsx("div", { className: "rounded-full bg-indigo-600 dark:bg-indigo-500 absolute text-xs h-4 w-4 flex items-center justify-center -top-3 -right-3 text-white text-[10px]", children: sumBy.length })) : null] })] }) }) }));
29
- };
@@ -1,4 +0,0 @@
1
- import { ProfileType } from '@parca/parser';
2
- export declare const DEFAULT_EMPTY_SUM_BY: string[];
3
- export declare const useSumBy: (profileType: ProfileType | undefined, labels: string[] | undefined) => [string[], (labels: string[]) => void];
4
- //# sourceMappingURL=useSumBy.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useSumBy.d.ts","sourceRoot":"","sources":["../../src/ProfileMetricsGraph/useSumBy.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAE1C,eAAO,MAAM,oBAAoB,EAAE,MAAM,EAAO,CAAC;AA6BjD,eAAO,MAAM,QAAQ,gBACN,WAAW,GAAG,SAAS,UAC5B,MAAM,EAAE,GAAG,SAAS,KAC3B,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAkEvC,CAAC"}
@@ -1,94 +0,0 @@
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
-
14
- import {ReactNode, useId, useMemo, useState} from 'react';
15
-
16
- import {Icon} from '@iconify/react';
17
- import Draggable from 'react-draggable';
18
- import Select from 'react-select';
19
-
20
- import {IconButton} from '@parca/components';
21
-
22
- interface Props {
23
- sumBy: string[];
24
- setSumBy: (sumBy: string[]) => void;
25
- labels: string[];
26
- }
27
-
28
- export const Toolbar = ({sumBy, setSumBy, labels}: Props): ReactNode => {
29
- const [collapsed, setCollapsed] = useState<boolean>(false);
30
- const [isDragging, setIsDragging] = useState<boolean>(false);
31
- const idWithColon = useId();
32
- const id = useMemo(() => idWithColon.replace(/[^a-zA-Z0-9]/g, ''), [idWithColon]);
33
-
34
- return (
35
- <Draggable
36
- handle={`#${id}`}
37
- onStart={() => setIsDragging(true)}
38
- onStop={() => setIsDragging(false)}
39
- bounds="parent"
40
- defaultPosition={{x: 96, y: 4}}
41
- >
42
- <div className="absolute rounded-full bg-gray-100 dark:bg-gray-800 z-10 text-xs">
43
- <div className="flex items-center h-14 gap-4 py-1 px-3">
44
- <Icon
45
- icon="radix-icons:drag-handle-dots-2"
46
- height={20}
47
- className={isDragging ? 'cursor-grabbing' : 'cursor-grab'}
48
- id={id}
49
- />
50
- {!collapsed ? (
51
- <div className="flex gap-2 items-center mr-4">
52
- <span>Sum by</span>
53
- <Select
54
- defaultValue={[]}
55
- isMulti
56
- name="colors"
57
- options={labels.map(label => ({label, value: label}))}
58
- className="parca-select-container min-w-60"
59
- classNamePrefix="parca-select"
60
- value={sumBy.map(sumBy => ({label: sumBy, value: sumBy}))}
61
- onChange={selectedOptions => {
62
- setSumBy(selectedOptions.map(option => option.value));
63
- }}
64
- placeholder="Labels..."
65
- styles={{
66
- indicatorSeparator: () => ({display: 'none'}),
67
- }}
68
- />
69
- </div>
70
- ) : null}
71
- <div className="relative">
72
- <IconButton
73
- icon={
74
- <Icon
75
- icon={
76
- collapsed ? 'iconamoon:arrow-right-2-light' : 'iconamoon:arrow-left-2-light'
77
- }
78
- height={24}
79
- />
80
- }
81
- onClick={() => setCollapsed(!collapsed)}
82
- className="hover:bg-gray-200 dark:hover:bg-gray-700 rounded-full p-1"
83
- />
84
- {collapsed && sumBy.length > 0 ? (
85
- <div className="rounded-full bg-indigo-600 dark:bg-indigo-500 absolute text-xs h-4 w-4 flex items-center justify-center -top-3 -right-3 text-white text-[10px]">
86
- {sumBy.length}
87
- </div>
88
- ) : null}
89
- </div>
90
- </div>
91
- </div>
92
- </Draggable>
93
- );
94
- };