@parca/profile 0.19.139 → 0.19.140

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 (132) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
  3. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +11 -13
  4. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
  5. package/dist/ProfileExplorer/ProfileExplorerCompare.js +4 -9
  6. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts +2 -2
  7. package/dist/ProfileFlameChart/SamplesStrips/index.d.ts.map +1 -1
  8. package/dist/ProfileFlameChart/index.d.ts.map +1 -1
  9. package/dist/ProfileFlameChart/index.js +13 -19
  10. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
  11. package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +8 -8
  12. package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.d.ts.map +1 -1
  13. package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.js +4 -3
  14. package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
  15. package/dist/ProfileFlameGraph/index.js +6 -4
  16. package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
  17. package/dist/ProfileMetricsGraph/index.js +4 -6
  18. package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
  19. package/dist/ProfileSelector/MetricsGraphSection.js +5 -10
  20. package/dist/ProfileSelector/index.d.ts.map +1 -1
  21. package/dist/ProfileSelector/index.js +27 -25
  22. package/dist/ProfileView/components/ActionButtons/SortByDropdown.d.ts.map +1 -1
  23. package/dist/ProfileView/components/ActionButtons/SortByDropdown.js +5 -5
  24. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
  25. package/dist/ProfileView/components/ColorStackLegend.js +2 -3
  26. package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -1
  27. package/dist/ProfileView/components/InvertCallStack/index.js +5 -4
  28. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +1 -2
  29. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
  30. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +14 -16
  31. package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.js +84 -170
  32. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
  33. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +16 -20
  34. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
  35. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +4 -5
  36. package/dist/ProfileView/components/Toolbars/index.d.ts +2 -2
  37. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
  38. package/dist/ProfileView/components/Toolbars/index.js +1 -1
  39. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
  40. package/dist/ProfileView/components/ViewSelector/index.js +8 -14
  41. package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -1
  42. package/dist/ProfileView/context/DashboardContext.js +6 -6
  43. package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -1
  44. package/dist/ProfileView/hooks/useResetFlameGraphState.js +5 -4
  45. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
  46. package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +25 -26
  47. package/dist/ProfileView/hooks/useResetStateOnSeriesChange.d.ts.map +1 -1
  48. package/dist/ProfileView/hooks/useResetStateOnSeriesChange.js +13 -8
  49. package/dist/ProfileView/hooks/useVisualizationState.d.ts +3 -3
  50. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
  51. package/dist/ProfileView/hooks/useVisualizationState.js +35 -51
  52. package/dist/ProfileViewWithData.d.ts.map +1 -1
  53. package/dist/ProfileViewWithData.js +19 -28
  54. package/dist/Sandwich/index.d.ts.map +1 -1
  55. package/dist/Sandwich/index.js +4 -3
  56. package/dist/SourceView/index.d.ts.map +1 -1
  57. package/dist/SourceView/index.js +4 -2
  58. package/dist/SourceView/useSelectedLineRange.d.ts.map +1 -1
  59. package/dist/SourceView/useSelectedLineRange.js +21 -16
  60. package/dist/Table/MoreDropdown.d.ts.map +1 -1
  61. package/dist/Table/MoreDropdown.js +8 -11
  62. package/dist/Table/TableContextMenu.d.ts.map +1 -1
  63. package/dist/Table/TableContextMenu.js +10 -13
  64. package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -1
  65. package/dist/Table/hooks/useTableConfiguration.js +3 -4
  66. package/dist/Table/index.d.ts.map +1 -1
  67. package/dist/Table/index.js +11 -9
  68. package/dist/TopTable/index.d.ts.map +1 -1
  69. package/dist/TopTable/index.js +3 -4
  70. package/dist/hooks/urlParsers.d.ts +18 -0
  71. package/dist/hooks/urlParsers.d.ts.map +1 -0
  72. package/dist/hooks/urlParsers.js +32 -0
  73. package/dist/hooks/useColorBy.d.ts +5 -0
  74. package/dist/hooks/useColorBy.d.ts.map +1 -0
  75. package/dist/hooks/useColorBy.js +26 -0
  76. package/dist/hooks/useCompareModeMeta.d.ts.map +1 -1
  77. package/dist/hooks/useCompareModeMeta.js +55 -86
  78. package/dist/hooks/useDashboardItems.d.ts +5 -0
  79. package/dist/hooks/useDashboardItems.d.ts.map +1 -0
  80. package/dist/hooks/useDashboardItems.js +27 -0
  81. package/dist/hooks/useQueryState.d.ts +3 -3
  82. package/dist/hooks/useQueryState.d.ts.map +1 -1
  83. package/dist/hooks/useQueryState.js +105 -105
  84. package/dist/hooks/useQueryState.test.js +186 -302
  85. package/dist/index.d.ts +3 -2
  86. package/dist/index.d.ts.map +1 -1
  87. package/dist/index.js +3 -12
  88. package/dist/useSumBy.d.ts +1 -1
  89. package/dist/useSumBy.d.ts.map +1 -1
  90. package/dist/useSumBy.js +2 -2
  91. package/package.json +8 -7
  92. package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +11 -13
  93. package/src/ProfileExplorer/ProfileExplorerCompare.tsx +4 -9
  94. package/src/ProfileFlameChart/SamplesStrips/index.tsx +2 -2
  95. package/src/ProfileFlameChart/index.tsx +21 -28
  96. package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +10 -9
  97. package/src/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.tsx +5 -3
  98. package/src/ProfileFlameGraph/index.tsx +6 -9
  99. package/src/ProfileMetricsGraph/index.tsx +6 -8
  100. package/src/ProfileSelector/MetricsGraphSection.tsx +5 -10
  101. package/src/ProfileSelector/index.tsx +32 -31
  102. package/src/ProfileView/components/ActionButtons/SortByDropdown.tsx +10 -6
  103. package/src/ProfileView/components/ColorStackLegend.tsx +2 -4
  104. package/src/ProfileView/components/InvertCallStack/index.tsx +5 -4
  105. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.tsx +94 -192
  106. package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +21 -21
  107. package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +24 -25
  108. package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +4 -5
  109. package/src/ProfileView/components/Toolbars/index.tsx +3 -3
  110. package/src/ProfileView/components/ViewSelector/index.tsx +9 -16
  111. package/src/ProfileView/context/DashboardContext.tsx +6 -6
  112. package/src/ProfileView/hooks/useResetFlameGraphState.ts +6 -4
  113. package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +24 -26
  114. package/src/ProfileView/hooks/useResetStateOnSeriesChange.ts +16 -8
  115. package/src/ProfileView/hooks/useVisualizationState.ts +61 -69
  116. package/src/ProfileViewWithData.tsx +29 -35
  117. package/src/Sandwich/index.tsx +4 -3
  118. package/src/SourceView/index.tsx +4 -2
  119. package/src/SourceView/useSelectedLineRange.ts +34 -19
  120. package/src/Table/MoreDropdown.tsx +9 -11
  121. package/src/Table/TableContextMenu.tsx +10 -13
  122. package/src/Table/hooks/useTableConfiguration.tsx +3 -4
  123. package/src/Table/index.tsx +12 -21
  124. package/src/TopTable/index.tsx +3 -4
  125. package/src/hooks/urlParsers.ts +38 -0
  126. package/src/hooks/useColorBy.ts +42 -0
  127. package/src/hooks/useCompareModeMeta.ts +61 -91
  128. package/src/hooks/useDashboardItems.ts +46 -0
  129. package/src/hooks/useQueryState.test.tsx +275 -345
  130. package/src/hooks/useQueryState.ts +136 -118
  131. package/src/index.tsx +16 -15
  132. package/src/useSumBy.ts +3 -3
@@ -22,7 +22,7 @@ export interface VisualisationToolbarProps {
22
22
  flamechartDimension: string[];
23
23
  setFlamechartDimension: (labels: string[]) => void;
24
24
  showVisualizationSelector?: boolean;
25
- sandwichFunctionName?: string;
25
+ sandwichFunctionName: string | null;
26
26
  alignFunctionName: string;
27
27
  setAlignFunctionName: (align: string) => void;
28
28
  colorBy: string;
@@ -44,7 +44,7 @@ export interface FlameGraphToolbarProps {
44
44
  }
45
45
  export interface SandwichFlameGraphToolbarProps {
46
46
  resetSandwichFunctionName: () => void;
47
- sandwichFunctionName?: string;
47
+ sandwichFunctionName: string | null;
48
48
  }
49
49
  export declare const TableToolbar: FC<TableToolbarProps>;
50
50
  export declare const FlameGraphToolbar: FC<FlameGraphToolbarProps>;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAoH9D,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/Toolbars/index.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAC,MAAM,OAAO,CAAC;AAIzB,OAAO,EAAC,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAEjD,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAG1C,OAAO,EAAC,gBAAgB,EAAC,MAAM,kDAAkD,CAAC;AAClF,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAUrD,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IAClD,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,6BAA6B,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAChD,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,QAAQ,EAAE;QACR,MAAM,EAAE,MAAM,EAAE,CAAC;QACjB,OAAO,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;QAC9B,OAAO,EAAE,OAAO,CAAC;KAClB,CAAC;CACH;AAED,MAAM,WAAW,iBAAiB;IAChC,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,gBAAgB,EAAE,CAAC;IAC5B,aAAa,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;CACnD;AAED,MAAM,WAAW,8BAA8B;IAC7C,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,eAAO,MAAM,YAAY,EAAE,EAAE,CAAC,iBAAiB,CAQ9C,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,sBAAsB,CAkBxD,CAAC;AAEF,eAAO,MAAM,yBAAyB,EAAE,EAAE,CAAC,8BAA8B,CAmBxE,CAAC;AAMF,eAAO,MAAM,oBAAoB,EAAE,EAAE,CAAC,yBAAyB,CAoH9D,CAAC"}
@@ -17,7 +17,7 @@ export const FlameGraphToolbar = ({ curPath, setNewCurPath }) => {
17
17
  return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end", children: _jsxs(Button, { variant: "neutral", className: "gap-2 w-max h-fit", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, id: "h-reset-graph", ...testId(TEST_IDS.FLAMEGRAPH_RESET_BUTTON), children: ["Reset graph", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }) }) }));
18
18
  };
19
19
  export const SandwichFlameGraphToolbar = ({ resetSandwichFunctionName, sandwichFunctionName, }) => {
20
- return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName === undefined || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
20
+ return (_jsx(_Fragment, { children: _jsx("div", { className: "flex w-full gap-2 items-end justify-between", children: _jsx(Button, { color: "neutral", onClick: () => resetSandwichFunctionName(), className: "w-auto", variant: "neutral", disabled: sandwichFunctionName == null || sandwichFunctionName.length === 0, children: "Reset view" }) }) }));
21
21
  };
22
22
  const Divider = () => (_jsx("div", { className: "border-t mt-4 border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" }));
23
23
  export const VisualisationToolbar = ({ groupBy, toggleGroupBy, setGroupByLabels, flamechartDimension, setFlamechartDimension, profileType, profileSource, queryClient, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, curPath, setNewCurPath, total, filtered, showVisualizationSelector = true, alignFunctionName, setAlignFunctionName, colorBy, setColorBy, metadata: { labels: groupByLabels, refetch: metadataRefetch, loading: metadataLoading }, }) => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ViewSelector/index.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAGrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,GAAI,mBAAiB,KAAK,KAAG,GAAG,CAAC,OA+JlD,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/ProfileView/components/ViewSelector/index.tsx"],"names":[],"mappings":"AAmBA,OAAO,EAAC,aAAa,EAAC,MAAM,wBAAwB,CAAC;AAKrD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;CAC/B;AAED,QAAA,MAAM,YAAY,GAAI,mBAAiB,KAAK,KAAG,GAAG,CAAC,OAoJlD,CAAC;AAEF,eAAe,YAAY,CAAC"}
@@ -1,13 +1,13 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { useParcaContext, useURLState, useURLStateBatch } from '@parca/components';
2
+ import { useQueryState } from 'nuqs';
3
+ import { useParcaContext } from '@parca/components';
4
+ import { stringParam } from '../../../hooks/urlParsers';
5
+ import { useDashboardItems } from '../../../hooks/useDashboardItems';
3
6
  import Dropdown from './Dropdown';
4
7
  const ViewSelector = ({ profileSource }) => {
5
- const [dashboardItems = ['flamegraph'], setDashboardItems] = useURLState('dashboard_items', {
6
- alwaysReturnArray: true,
7
- });
8
- const [, setSandwichFunctionName] = useURLState('sandwich_function_name');
8
+ const { dashboardItems, setDashboardItems } = useDashboardItems();
9
+ const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
9
10
  const { enableSourcesView, enableSandwichView } = useParcaContext();
10
- const batchUpdates = useURLStateBatch();
11
11
  const allItems = [
12
12
  {
13
13
  key: 'flamegraph',
@@ -61,15 +61,9 @@ const ViewSelector = ({ profileSource }) => {
61
61
  }
62
62
  else {
63
63
  const newDashboardItems = dashboardItems.filter(v => v !== item.key);
64
- // Batch updates when removing sandwich panel to combine both URL changes
64
+ setDashboardItems(newDashboardItems);
65
65
  if (item.key === 'sandwich') {
66
- batchUpdates(() => {
67
- setDashboardItems(newDashboardItems);
68
- setSandwichFunctionName(undefined);
69
- });
70
- }
71
- else {
72
- setDashboardItems(newDashboardItems);
66
+ void setSandwichFunctionName(null);
73
67
  }
74
68
  }
75
69
  },
@@ -1 +1 @@
1
- {"version":3,"file":"DashboardContext.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/context/DashboardContext.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAA4B,MAAM,OAAO,CAAC;AAIvE,OAAO,EAAC,iBAAiB,EAAC,MAAM,wBAAwB,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,gBAAgB,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CA8BnD,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,oBAM/B,CAAC"}
1
+ {"version":3,"file":"DashboardContext.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/context/DashboardContext.tsx"],"names":[],"mappings":"AAaA,OAAO,EAAC,EAAE,EAAE,iBAAiB,EAA4B,MAAM,OAAO,CAAC;AAMvE,OAAO,EAAC,iBAAiB,EAAC,MAAM,wBAAwB,CAAC;AAEzD,UAAU,oBAAoB;IAC5B,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,iBAAiB,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,gBAAgB,EAAE,CAAC,iBAAiB,EAAE,iBAAiB,KAAK,IAAI,CAAC;IACjE,gBAAgB,EAAE,OAAO,CAAC;CAC3B;AAID,eAAO,MAAM,iBAAiB,EAAE,EAAE,CAAC,iBAAiB,CA4BnD,CAAC;AAEF,eAAO,MAAM,YAAY,QAAO,oBAM/B,CAAC"}
@@ -12,19 +12,19 @@ import { jsx as _jsx } from "react/jsx-runtime";
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { createContext, useContext } from 'react';
15
- import { useURLState } from '@parca/components';
15
+ import { useQueryState } from 'nuqs';
16
+ import { stringParam } from '../../hooks/urlParsers';
17
+ import { useDashboardItems } from '../../hooks/useDashboardItems';
16
18
  const DashboardContext = createContext(undefined);
17
19
  export const DashboardProvider = ({ children }) => {
18
- const [dashboardItems, setDashboardItems] = useURLState('dashboard_items', {
19
- alwaysReturnArray: true,
20
- });
21
- const [, setSandwichFunctionName] = useURLState('sandwich_function_name');
20
+ const { dashboardItems, setDashboardItems } = useDashboardItems();
21
+ const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
22
22
  const handleClosePanel = (visualizationType) => {
23
23
  const newDashboardItems = dashboardItems.filter(item => item !== visualizationType);
24
24
  setDashboardItems(newDashboardItems);
25
25
  // Reset sandwich function name when closing sandwich panel
26
26
  if (visualizationType === 'sandwich') {
27
- setSandwichFunctionName(undefined);
27
+ void setSandwichFunctionName(null);
28
28
  }
29
29
  };
30
30
  const isMultiPanelView = dashboardItems.length > 1;
@@ -1 +1 @@
1
- {"version":3,"file":"useResetFlameGraphState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetFlameGraphState.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,uBAAuB,QAAO,CAAC,MAAM,IAAI,CAWrD,CAAC"}
1
+ {"version":3,"file":"useResetFlameGraphState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetFlameGraphState.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,uBAAuB,QAAO,CAAC,MAAM,IAAI,CAWrD,CAAC"}
@@ -10,15 +10,16 @@
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 { useURLState } from '@parca/components';
13
+ import { useQueryState } from 'nuqs';
14
+ import { stringParam } from '../../hooks/urlParsers';
14
15
  export const useResetFlameGraphState = () => {
15
- const [val, setCurPath] = useURLState('cur_path');
16
+ const [val, setCurPath] = useQueryState('cur_path', stringParam);
16
17
  return () => {
17
18
  setTimeout(() => {
18
- if (val === undefined) {
19
+ if (val === null) {
19
20
  return;
20
21
  }
21
- setCurPath(undefined);
22
+ void setCurPath(null);
22
23
  });
23
24
  };
24
25
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useResetStateOnProfileTypeChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,gCAAgC,QAAO,CAAC,MAAM,IAAI,CA+B9D,CAAC"}
1
+ {"version":3,"file":"useResetStateOnProfileTypeChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts"],"names":[],"mappings":"AAkBA,eAAO,MAAM,gCAAgC,QAAO,CAAC,MAAM,IAAI,CA4B9D,CAAC"}
@@ -10,35 +10,34 @@
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 { useURLState, useURLStateBatch } from '@parca/components';
13
+ import { useQueryStates } from 'nuqs';
14
+ import { stringParam } from '../../hooks/urlParsers';
14
15
  import { useProfileFilters } from '../components/ProfileFilters/useProfileFilters';
15
16
  export const useResetStateOnProfileTypeChange = () => {
16
- const [groupBy, setGroupBy] = useURLState('group_by');
17
- const [curPath, setCurPath] = useURLState('cur_path');
18
- const [sumByA, setSumByA] = useURLState('sum_by_a');
19
- const [sumByB, setSumByB] = useURLState('sum_by_b');
17
+ const [state, setState] = useQueryStates({
18
+ group_by: stringParam,
19
+ cur_path: stringParam,
20
+ sum_by_a: stringParam,
21
+ sum_by_b: stringParam,
22
+ sandwich_function_name: stringParam,
23
+ }, { history: 'replace' });
20
24
  const { resetFilters } = useProfileFilters();
21
- const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
22
- const batchUpdates = useURLStateBatch();
23
25
  return () => {
24
- // Batch all URL state resets into a single navigation
25
- batchUpdates(() => {
26
- if (groupBy !== undefined) {
27
- setGroupBy(undefined);
28
- }
29
- if (curPath !== undefined) {
30
- setCurPath(undefined);
31
- }
32
- if (sandwichFunctionName !== undefined) {
33
- setSandwichFunctionName(undefined);
34
- }
35
- if (sumByA !== undefined) {
36
- setSumByA(undefined);
37
- }
38
- if (sumByB !== undefined) {
39
- setSumByB(undefined);
40
- }
41
- resetFilters();
42
- });
26
+ // Atomic reset: clear all params in single URL update
27
+ const updates = {};
28
+ if (state.group_by !== null)
29
+ updates.group_by = null;
30
+ if (state.cur_path !== null)
31
+ updates.cur_path = null;
32
+ if (state.sandwich_function_name !== null)
33
+ updates.sandwich_function_name = null;
34
+ if (state.sum_by_a !== null)
35
+ updates.sum_by_a = null;
36
+ if (state.sum_by_b !== null)
37
+ updates.sum_by_b = null;
38
+ if (Object.keys(updates).length > 0) {
39
+ void setState(updates);
40
+ }
41
+ resetFilters();
43
42
  };
44
43
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useResetStateOnSeriesChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnSeriesChange.ts"],"names":[],"mappings":"AAeA,eAAO,MAAM,2BAA2B,QAAO,CAAC,MAAM,IAAI,CAczD,CAAC"}
1
+ {"version":3,"file":"useResetStateOnSeriesChange.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useResetStateOnSeriesChange.ts"],"names":[],"mappings":"AAiBA,eAAO,MAAM,2BAA2B,QAAO,CAAC,MAAM,IAAI,CAoBzD,CAAC"}
@@ -10,17 +10,22 @@
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 { useURLState } from '@parca/components';
13
+ import { useQueryStates } from 'nuqs';
14
+ import { stringParam } from '../../hooks/urlParsers';
14
15
  export const useResetStateOnSeriesChange = () => {
15
- const [curPath, setCurPath] = useURLState('cur_path');
16
- const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
16
+ const [state, setState] = useQueryStates({
17
+ cur_path: stringParam,
18
+ sandwich_function_name: stringParam,
19
+ }, { history: 'replace' });
17
20
  return () => {
18
21
  setTimeout(() => {
19
- if (curPath !== undefined) {
20
- setCurPath(undefined);
21
- }
22
- if (sandwichFunctionName !== undefined) {
23
- setSandwichFunctionName(undefined);
22
+ const updates = {};
23
+ if (state.cur_path !== null)
24
+ updates.cur_path = null;
25
+ if (state.sandwich_function_name !== null)
26
+ updates.sandwich_function_name = null;
27
+ if (Object.keys(updates).length > 0) {
28
+ void setState(updates);
24
29
  }
25
30
  });
26
31
  };
@@ -2,7 +2,7 @@ import { CurrentPathFrame } from '../../ProfileFlameGraph/FlameGraphArrow/utils'
2
2
  export declare const useVisualizationState: () => {
3
3
  curPathArrow: CurrentPathFrame[];
4
4
  setCurPathArrow: (path: CurrentPathFrame[]) => void;
5
- colorStackLegend: string | undefined;
5
+ colorStackLegend: string | null;
6
6
  colorBy: string;
7
7
  setColorBy: (colorBy: string) => void;
8
8
  groupBy: string[];
@@ -11,8 +11,8 @@ export declare const useVisualizationState: () => {
11
11
  setGroupByLabels: (labels: string[]) => void;
12
12
  flamechartDimension: string[];
13
13
  setFlamechartDimension: (labels: string[]) => void;
14
- sandwichFunctionName: string | undefined;
15
- setSandwichFunctionName: (sandwichFunctionName: string | undefined) => void;
14
+ sandwichFunctionName: string | null;
15
+ setSandwichFunctionName: (sandwichFunctionName: string | null) => void;
16
16
  resetSandwichFunctionName: () => void;
17
17
  alignFunctionName: string;
18
18
  setAlignFunctionName: (align: string) => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA+BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAG/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC5E,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAgI/C,CAAC"}
1
+ {"version":3,"file":"useVisualizationState.d.ts","sourceRoot":"","sources":["../../../src/ProfileView/hooks/useVisualizationState.ts"],"names":[],"mappings":"AA0BA,OAAO,EAAC,gBAAgB,EAAC,MAAM,+CAA+C,CAAC;AAU/E,eAAO,MAAM,qBAAqB,QAAO;IACvC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,eAAe,EAAE,CAAC,IAAI,EAAE,gBAAgB,EAAE,KAAK,IAAI,CAAC;IACpD,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACrC,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IAC7C,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,sBAAsB,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACnD,oBAAoB,EAAE,MAAM,GAAG,IAAI,CAAC;IACpC,uBAAuB,EAAE,CAAC,oBAAoB,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IACvE,yBAAyB,EAAE,MAAM,IAAI,CAAC;IACtC,iBAAiB,EAAE,MAAM,CAAC;IAC1B,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;CAsH/C,CAAC"}
@@ -11,35 +11,29 @@
11
11
  // See the License for the specific language governing permissions and
12
12
  // limitations under the License.
13
13
  import { useCallback, useMemo } from 'react';
14
- import { JSONParser, JSONSerializer, useURLState, useURLStateBatch, useURLStateCustom, } from '@parca/components';
14
+ import { useQueryState } from 'nuqs';
15
15
  import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
16
16
  import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../ProfileFlameGraph/FlameGraphArrow';
17
+ import { flamechartDimensionParser, groupByParser, jsonParser, stringParam, } from '../../hooks/urlParsers';
18
+ import { useColorBy } from '../../hooks/useColorBy';
17
19
  import { useResetFlameGraphState } from './useResetFlameGraphState';
18
20
  export const useVisualizationState = () => {
19
- const [colorByPreference, setColorByPreference] = useUserPreference(USER_PREFERENCES.COLOR_BY.key);
20
21
  const [alignFunctionNamePreference, setAlignFunctionNamePreference] = useUserPreference(USER_PREFERENCES.ALIGN_FUNCTION_NAME.key);
21
- const [curPathArrow, setCurPathArrow] = useURLStateCustom('cur_path', {
22
- parse: (JSONParser),
23
- stringify: JSONSerializer,
24
- defaultValue: '[]',
25
- });
26
- const [colorStackLegend] = useURLState('color_stack_legend');
27
- const [colorBy, setStoreColorBy] = useURLState('color_by', {
28
- defaultValue: colorByPreference,
29
- });
30
- const [alignFunctionName, setStoreAlignFunctionName] = useURLState('align_function_name', {
31
- defaultValue: alignFunctionNamePreference,
32
- });
33
- const [groupBy, setStoreGroupBy] = useURLState('group_by', {
34
- defaultValue: [FIELD_FUNCTION_NAME],
35
- alwaysReturnArray: true,
36
- });
37
- const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
38
- const [flamechartDimension, setStoreFlamechartDimension] = useURLState('flamechart_dimension', {
39
- alwaysReturnArray: true,
40
- });
22
+ const [curPathArrow, setRawCurPathArrow] = useQueryState('cur_path', jsonParser().withDefault([]));
23
+ const setCurPathArrow = useCallback((path) => {
24
+ void setRawCurPathArrow(path);
25
+ }, [setRawCurPathArrow]);
26
+ const [colorStackLegend] = useQueryState('color_stack_legend', stringParam);
27
+ const { colorBy, setColorBy } = useColorBy();
28
+ const [alignFunctionNameRaw, setStoreAlignFunctionName] = useQueryState('align_function_name', stringParam);
29
+ const alignFunctionName = alignFunctionNameRaw ?? alignFunctionNamePreference ?? 'left';
30
+ const [groupBy, setStoreGroupBy] = useQueryState('group_by', groupByParser.withDefault([FIELD_FUNCTION_NAME]));
31
+ const [sandwichFunctionName, setRawSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
32
+ const setSandwichFunctionName = useCallback((name) => {
33
+ void setRawSandwichFunctionName(name);
34
+ }, [setRawSandwichFunctionName]);
35
+ const [flamechartDimension, setStoreFlamechartDimension] = useQueryState('flamechart_dimension', flamechartDimensionParser.withDefault([]));
41
36
  const resetFlameGraphState = useResetFlameGraphState();
42
- const batchUpdates = useURLStateBatch();
43
37
  const levelsOfProfiling = useMemo(() => [
44
38
  FIELD_FUNCTION_NAME,
45
39
  FIELD_FUNCTION_FILE_NAME,
@@ -47,47 +41,37 @@ export const useVisualizationState = () => {
47
41
  FIELD_MAPPING_FILE,
48
42
  ], []);
49
43
  const setGroupBy = useCallback((keys) => {
50
- setStoreGroupBy(keys);
44
+ void setStoreGroupBy(keys);
51
45
  }, [setStoreGroupBy]);
52
46
  const toggleGroupBy = useCallback((key) => {
53
- // Batch updates to combine setGroupBy + resetFlameGraphState into single URL navigation
54
- batchUpdates(() => {
55
- if (groupBy.includes(key)) {
56
- setGroupBy(groupBy.filter(v => v !== key)); // remove
57
- }
58
- else {
59
- const filteredGroupBy = groupBy.filter(item => !levelsOfProfiling.includes(item));
60
- setGroupBy([...filteredGroupBy, key]); // add
61
- }
62
- resetFlameGraphState();
63
- });
64
- }, [groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState, batchUpdates]);
47
+ if (groupBy.includes(key)) {
48
+ setGroupBy(groupBy.filter(v => v !== key));
49
+ }
50
+ else {
51
+ const filteredGroupBy = groupBy.filter(item => !levelsOfProfiling.includes(item));
52
+ setGroupBy([...filteredGroupBy, key]);
53
+ }
54
+ resetFlameGraphState();
55
+ }, [groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState]);
65
56
  const setGroupByLabels = useCallback((labels) => {
66
- // Batch updates to combine setGroupBy + resetFlameGraphState into single URL navigation
67
- batchUpdates(() => {
68
- setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
69
- resetFlameGraphState();
70
- });
71
- }, [groupBy, setGroupBy, resetFlameGraphState, batchUpdates]);
57
+ setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
58
+ resetFlameGraphState();
59
+ }, [groupBy, setGroupBy, resetFlameGraphState]);
72
60
  const setFlamechartDimension = useCallback((labels) => {
73
- setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
61
+ void setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
74
62
  }, [setStoreFlamechartDimension]);
75
63
  const resetSandwichFunctionName = useCallback(() => {
76
- setSandwichFunctionName(undefined);
64
+ setSandwichFunctionName(null);
77
65
  }, [setSandwichFunctionName]);
78
- const setColorBy = useCallback((value) => {
79
- setStoreColorBy(value);
80
- setColorByPreference(value);
81
- }, [setStoreColorBy, setColorByPreference]);
82
66
  const setAlignFunctionName = useCallback((value) => {
83
- setStoreAlignFunctionName(value);
67
+ void setStoreAlignFunctionName(value);
84
68
  setAlignFunctionNamePreference(value);
85
69
  }, [setStoreAlignFunctionName, setAlignFunctionNamePreference]);
86
70
  return {
87
71
  curPathArrow,
88
72
  setCurPathArrow,
89
73
  colorStackLegend,
90
- colorBy: colorBy ?? '',
74
+ colorBy,
91
75
  setColorBy,
92
76
  groupBy,
93
77
  setGroupBy,
@@ -98,7 +82,7 @@ export const useVisualizationState = () => {
98
82
  sandwichFunctionName,
99
83
  setSandwichFunctionName,
100
84
  resetSandwichFunctionName,
101
- alignFunctionName: alignFunctionName ?? 'left',
85
+ alignFunctionName,
102
86
  setAlignFunctionName,
103
87
  };
104
88
  };
@@ -1 +1 @@
1
- {"version":3,"file":"ProfileViewWithData.d.ts","sourceRoot":"","sources":["../src/ProfileViewWithData.tsx"],"names":[],"mappings":"AAeA,OAAO,EAA0B,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAkB1E,OAAO,EAAsB,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAOnE,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,mBAAmB,GAAI,sFAKjC,wBAAwB,KAAG,GAAG,CAAC,OA4UjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
1
+ {"version":3,"file":"ProfileViewWithData.d.ts","sourceRoot":"","sources":["../src/ProfileViewWithData.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAA0B,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAW1E,OAAO,EAAsB,aAAa,EAAC,MAAM,iBAAiB,CAAC;AAenE,UAAU,wBAAwB;IAChC,WAAW,EAAE,kBAAkB,CAAC;IAChC,aAAa,EAAE,aAAa,CAAC;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yBAAyB,CAAC,EAAE,OAAO,CAAC;IACpC,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,mBAAmB,GAAI,sFAKjC,wBAAwB,KAAG,GAAG,CAAC,OAmUjC,CAAC;AAEF,eAAe,mBAAmB,CAAC"}
@@ -12,8 +12,9 @@ import { jsx as _jsx } from "react/jsx-runtime";
12
12
  // See the License for the specific language governing permissions and
13
13
  // limitations under the License.
14
14
  import { useEffect, useMemo, useState } from 'react';
15
+ import { useQueryState } from 'nuqs';
15
16
  import { QueryRequest_ReportType } from '@parca/client';
16
- import { NumberParser, NumberSerializer, useGrpcMetadata, useParcaContext, useURLState, useURLStateCustom, } from '@parca/components';
17
+ import { useGrpcMetadata, useParcaContext } from '@parca/components';
17
18
  import { saveAsBlob } from '@parca/utilities';
18
19
  import { validateFlameChartQuery } from './ProfileFlameGraph';
19
20
  import { FIELD_FUNCTION_NAME } from './ProfileFlameGraph/FlameGraphArrow';
@@ -21,25 +22,19 @@ import { boundsFromProfileSource } from './ProfileFlameGraph/FlameGraphArrow/uti
21
22
  import { getStepCountFromScreenWidth, useQueryRange, } from './ProfileMetricsGraph/hooks/useQueryRange';
22
23
  import { ProfileView } from './ProfileView';
23
24
  import { useProfileFilters } from './ProfileView/components/ProfileFilters/useProfileFilters';
25
+ import { flamechartDimensionParser, groupByParser, intParam, invertCallStackParser, stringParam, } from './hooks/urlParsers';
26
+ import { useDashboardItems } from './hooks/useDashboardItems';
24
27
  import { useQuery } from './useQuery';
25
28
  import { downloadPprof } from './utils';
26
29
  export const ProfileViewWithData = ({ queryClient, profileSource, showVisualizationSelector, onSwitchToFifteenMinutes, }) => {
27
30
  const metadata = useGrpcMetadata();
28
- const [dashboardItems, setDashboardItems] = useURLState('dashboard_items', {
29
- alwaysReturnArray: true,
30
- });
31
- const [sourceBuildID] = useURLState('source_buildid');
32
- const [sourceFilename] = useURLState('source_filename');
33
- const [groupBy] = useURLState('group_by', {
34
- defaultValue: [FIELD_FUNCTION_NAME],
35
- alwaysReturnArray: true,
36
- });
37
- const [sandwichFunctionName] = useURLState('sandwich_function_name');
38
- const [flamechartDimension] = useURLState('flamechart_dimension', {
39
- alwaysReturnArray: true,
40
- });
41
- const [invertStack] = useURLState('invert_call_stack');
42
- const invertCallStack = invertStack === 'true';
31
+ const { dashboardItems, setDashboardItems } = useDashboardItems();
32
+ const [sourceBuildID] = useQueryState('source_buildid', stringParam);
33
+ const [sourceFilename] = useQueryState('source_filename', stringParam);
34
+ const [groupBy] = useQueryState('group_by', groupByParser.withDefault([FIELD_FUNCTION_NAME]));
35
+ const [sandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
36
+ const [flamechartDimension] = useQueryState('flamechart_dimension', flamechartDimensionParser);
37
+ const [invertCallStack] = useQueryState('invert_call_stack', invertCallStackParser);
43
38
  const [pprofDownloading, setPprofDownloading] = useState(false);
44
39
  const { protoFilters } = useProfileFilters();
45
40
  useEffect(() => {
@@ -73,7 +68,7 @@ export const ProfileViewWithData = ({ queryClient, profileSource, showVisualizat
73
68
  skip: !dashboardItems.includes('flamegraph'),
74
69
  nodeTrimThreshold,
75
70
  groupBy,
76
- invertCallStack,
71
+ invertCallStack: invertCallStack ?? false,
77
72
  protoFilters,
78
73
  });
79
74
  const samplesEnabled = !!(dashboardItems.includes('flamechart') &&
@@ -85,11 +80,7 @@ export const ProfileViewWithData = ({ queryClient, profileSource, showVisualizat
85
80
  }, [profileSource]);
86
81
  const samplesSumBy = useMemo(() => (flamechartDimension ?? []).map(f => f.startsWith('labels.') ? f.slice('labels.'.length) : f), [flamechartDimension]);
87
82
  // Samples step count: 2px per data point for finer granularity in strips
88
- const [samplesStepCount] = useURLStateCustom('samples_step_count', {
89
- defaultValue: String(getStepCountFromScreenWidth(2)),
90
- parse: NumberParser,
91
- stringify: NumberSerializer,
92
- });
83
+ const [samplesStepCount] = useQueryState('samples_step_count', intParam.withDefault(getStepCountFromScreenWidth(2)));
93
84
  const { isLoading: samplesLoading, response: samplesRangeResponse, error: samplesError, stepDurationMs: samplesStepMs, } = useQueryRange(queryClient, samplesEnabled ? profileSource.query.toString() : '', samplesFromMs, samplesToMs, samplesSumBy, samplesStepCount, !samplesEnabled);
94
85
  // Map QueryRange response to SamplesData
95
86
  // TODO (manoj): Check if we can skip this mapping and adapt the CPUSampleStrips to work directly with the QueryRange response format.
@@ -123,24 +114,24 @@ export const ProfileViewWithData = ({ queryClient, profileSource, showVisualizat
123
114
  });
124
115
  const { isLoading: sourceLoading, response: sourceResponse, error: sourceError, } = useQuery(queryClient, profileSource, QueryRequest_ReportType.SOURCE, {
125
116
  skip: !dashboardItems.includes('source'),
126
- sourceBuildID,
127
- sourceFilename,
117
+ sourceBuildID: sourceBuildID ?? undefined,
118
+ sourceFilename: sourceFilename ?? undefined,
128
119
  protoFilters,
129
120
  });
130
121
  const { isLoading: callersFlamegraphLoading, response: callersFlamegraphResponse, error: callersFlamegraphError, } = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_ARROW, {
131
122
  nodeTrimThreshold,
132
123
  groupBy: [FIELD_FUNCTION_NAME],
133
124
  invertCallStack: true,
134
- sandwichByFunction: sandwichFunctionName,
135
- skip: sandwichFunctionName === undefined && !dashboardItems.includes('sandwich'),
125
+ sandwichByFunction: sandwichFunctionName ?? undefined,
126
+ skip: sandwichFunctionName == null && !dashboardItems.includes('sandwich'),
136
127
  protoFilters,
137
128
  });
138
129
  const { isLoading: calleesFlamegraphLoading, response: calleesFlamegraphResponse, error: calleesFlamegraphError, } = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_ARROW, {
139
130
  nodeTrimThreshold,
140
131
  groupBy: [FIELD_FUNCTION_NAME],
141
132
  invertCallStack: false,
142
- sandwichByFunction: sandwichFunctionName,
143
- skip: sandwichFunctionName === undefined && !dashboardItems.includes('sandwich'),
133
+ sandwichByFunction: sandwichFunctionName ?? undefined,
134
+ skip: sandwichFunctionName == null && !dashboardItems.includes('sandwich'),
144
135
  protoFilters,
145
136
  });
146
137
  useEffect(() => {
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Sandwich/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAO9C,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAC,YAAY,EAAC,MAAM,oCAAoC,CAAC;AAIhE,UAAU,KAAK;IACb,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,QAAA,MAAM,QAAQ,mCAuEZ,CAAC;AAEH,eAAe,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Sandwich/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAyB,MAAM,OAAO,CAAC;AAO9C,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAG/C,OAAO,EAAC,YAAY,EAAC,MAAM,oCAAoC,CAAC;AAKhE,UAAU,KAAK;IACb,aAAa,EAAE,aAAa,CAAC;IAC7B,YAAY,EAAE,YAAY,CAAC;CAC5B;AAED,QAAA,MAAM,QAAQ,mCAuEZ,CAAC;AAEH,eAAe,QAAQ,CAAC"}
@@ -13,21 +13,22 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
13
13
  // limitations under the License.
14
14
  import React, { useRef, useState } from 'react';
15
15
  import { AnimatePresence, motion } from 'framer-motion';
16
- import { useURLState } from '@parca/components';
16
+ import { useQueryState } from 'nuqs';
17
17
  import { TEST_IDS, testId } from '@parca/test-utils';
18
18
  import { useDashboard } from '../ProfileView/context/DashboardContext';
19
19
  import { useVisualizationState } from '../ProfileView/hooks/useVisualizationState';
20
+ import { stringParam } from '../hooks/urlParsers';
20
21
  import { CalleesSection } from './components/CalleesSection';
21
22
  import { CallersSection } from './components/CallersSection';
22
23
  const Sandwich = React.memo(function Sandwich({ sandwichData, profileSource, }) {
23
24
  const { dashboardItems } = useDashboard();
24
- const [sandwichFunctionName] = useURLState('sandwich_function_name');
25
+ const [sandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
25
26
  const callersRef = React.useRef(null);
26
27
  const calleesRef = React.useRef(null);
27
28
  const [isExpanded, setIsExpanded] = useState(false);
28
29
  const defaultMaxFrames = 10;
29
30
  const callersCalleesContainerRef = useRef(null);
30
31
  const { curPathArrow, setCurPathArrow } = useVisualizationState();
31
- return (_jsx("section", { className: "flex flex-row h-full w-full", ...testId(TEST_IDS.SANDWICH_CONTAINER), children: _jsx(AnimatePresence, { children: _jsx(motion.div, { className: "h-full w-full", initial: { display: 'none', opacity: 0 }, animate: { display: 'block', opacity: 1 }, transition: { duration: 0.5 }, children: _jsx("div", { className: "relative flex flex-row", children: sandwichFunctionName !== undefined ? (_jsxs("div", { className: "w-full flex flex-col", ref: callersCalleesContainerRef, children: [_jsx(CallersSection, { callersRef: callersRef, callersFlamegraphData: sandwichData.callers, profileSource: profileSource, curPathArrow: curPathArrow, setCurPathArrow: setCurPathArrow, isExpanded: isExpanded, setIsExpanded: setIsExpanded, defaultMaxFrames: defaultMaxFrames }), _jsx("div", { className: "h-4" }), _jsx(CalleesSection, { calleesRef: calleesRef, calleesFlamegraphData: sandwichData.callees, profileSource: profileSource, curPathArrow: curPathArrow, setCurPathArrow: setCurPathArrow })] })) : (_jsx("div", { className: "items-center justify-center flex h-full w-full", ...testId(TEST_IDS.SANDWICH_NO_FUNCTION_SELECTED), children: _jsx("p", { className: "text-sm", children: dashboardItems.includes('table') ? ('Please select a function to view its callers and callees.') : (_jsxs(_Fragment, { children: ["Use the right-click menu on the Flame", ' ', dashboardItems.includes('flamegraph') ? 'Graph' : 'Chart', " to choose a function to view its callers and callees."] })) }) })) }) }, "sandwich-loaded") }) }));
32
+ return (_jsx("section", { className: "flex flex-row h-full w-full", ...testId(TEST_IDS.SANDWICH_CONTAINER), children: _jsx(AnimatePresence, { children: _jsx(motion.div, { className: "h-full w-full", initial: { display: 'none', opacity: 0 }, animate: { display: 'block', opacity: 1 }, transition: { duration: 0.5 }, children: _jsx("div", { className: "relative flex flex-row", children: sandwichFunctionName != null ? (_jsxs("div", { className: "w-full flex flex-col", ref: callersCalleesContainerRef, children: [_jsx(CallersSection, { callersRef: callersRef, callersFlamegraphData: sandwichData.callers, profileSource: profileSource, curPathArrow: curPathArrow, setCurPathArrow: setCurPathArrow, isExpanded: isExpanded, setIsExpanded: setIsExpanded, defaultMaxFrames: defaultMaxFrames }), _jsx("div", { className: "h-4" }), _jsx(CalleesSection, { calleesRef: calleesRef, calleesFlamegraphData: sandwichData.callees, profileSource: profileSource, curPathArrow: curPathArrow, setCurPathArrow: setCurPathArrow })] })) : (_jsx("div", { className: "items-center justify-center flex h-full w-full", ...testId(TEST_IDS.SANDWICH_NO_FUNCTION_SELECTED), children: _jsx("p", { className: "text-sm", children: dashboardItems.includes('table') ? ('Please select a function to view its callers and callees.') : (_jsxs(_Fragment, { children: ["Use the right-click menu on the Flame", ' ', dashboardItems.includes('flamegraph') ? 'Graph' : 'Chart', " to choose a function to view its callers and callees."] })) }) })) }) }, "sandwich-loaded") }) }));
32
33
  });
33
34
  export default Sandwich;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SourceView/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAM7D,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AAQrC,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;CACnD;AAID,eAAO,MAAM,UAAU,6CAqKrB,CAAC;AAEH,eAAe,UAAU,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/SourceView/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAwC,MAAM,OAAO,CAAC;AAO7D,OAAO,EAAC,MAAM,EAAC,MAAM,eAAe,CAAC;AASrC,UAAU,eAAe;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;CACnD;AAID,eAAO,MAAM,UAAU,6CAqKrB,CAAC;AAEH,eAAe,UAAU,CAAC"}
@@ -14,15 +14,17 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
14
14
  import React, { useCallback, useEffect, useMemo } from 'react';
15
15
  import { tableFromIPC } from '@uwdata/flechette';
16
16
  import { AnimatePresence, motion } from 'framer-motion';
17
+ import { useQueryState } from 'nuqs';
17
18
  import { Item, Menu, useContextMenu } from 'react-contexify';
18
- import { SourceSkeleton, useParcaContext, useURLState } from '@parca/components';
19
+ import { SourceSkeleton, useParcaContext } from '@parca/components';
19
20
  import { ExpandOnHover } from '../GraphTooltipArrow/ExpandOnHoverValue';
21
+ import { stringParam } from '../hooks/urlParsers';
20
22
  import { alignedUint8Array, truncateStringReverse } from '../utils';
21
23
  import { Highlighter, profileAwareRenderer } from './Highlighter';
22
24
  import useLineRange from './useSelectedLineRange';
23
25
  const MENU_ID = 'source-view-context-menu';
24
26
  export const SourceView = React.memo(function SourceView({ data, loading, total, filtered, setActionButtons, }) {
25
- const [sourceFileName] = useURLState('source_filename');
27
+ const [sourceFileName] = useQueryState('source_filename', stringParam);
26
28
  const { isDarkMode, sourceViewContextMenuItems = [] } = useParcaContext();
27
29
  const sourceCode = useMemo(() => {
28
30
  if (data === undefined) {
@@ -1 +1 @@
1
- {"version":3,"file":"useSelectedLineRange.d.ts","sourceRoot":"","sources":["../../src/SourceView/useSelectedLineRange.ts"],"names":[],"mappings":"AAiBA,UAAU,SAAS;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAED,QAAA,MAAM,YAAY,QAAO,SAmBxB,CAAC;AAEF,eAAe,YAAY,CAAC"}
1
+ {"version":3,"file":"useSelectedLineRange.d.ts","sourceRoot":"","sources":["../../src/SourceView/useSelectedLineRange.ts"],"names":[],"mappings":"AAiCA,UAAU,SAAS;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACpD;AAED,QAAA,MAAM,YAAY,QAAO,SAkBxB,CAAC;AAEF,eAAe,YAAY,CAAC"}