@parca/profile 0.19.142 → 0.19.143
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +4 -0
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +22 -28
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +72 -73
- package/dist/ProfileFlameChart/SamplesStrips/index.d.ts +2 -2
- package/dist/ProfileFlameChart/SamplesStrips/index.d.ts.map +1 -1
- package/dist/ProfileFlameChart/index.d.ts.map +1 -1
- package/dist/ProfileFlameChart/index.js +20 -24
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +13 -14
- package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.js +6 -5
- package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/index.js +8 -7
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +6 -8
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +48 -55
- package/dist/ProfileSelector/index.d.ts +1 -1
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +216 -210
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts +1 -3
- package/dist/ProfileSelector/useAutoQuerySelector.d.ts.map +1 -1
- package/dist/ProfileSelector/useAutoQuerySelector.js +133 -104
- package/dist/ProfileView/components/ActionButtons/SortByDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/ActionButtons/SortByDropdown.js +24 -25
- package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileView/components/ColorStackLegend.js +3 -5
- package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -1
- package/dist/ProfileView/components/InvertCallStack/index.js +47 -47
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +1 -2
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +37 -34
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +282 -294
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +7 -8
- package/dist/ProfileView/components/Toolbars/index.d.ts +2 -2
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +1 -1
- package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/index.js +53 -75
- package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -1
- package/dist/ProfileView/context/DashboardContext.js +36 -44
- package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetFlameGraphState.js +8 -7
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +59 -59
- package/dist/ProfileView/hooks/useResetStateOnSeriesChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnSeriesChange.js +37 -22
- package/dist/ProfileView/hooks/useVisualizationState.d.ts +3 -3
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +116 -147
- package/dist/ProfileViewWithData.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +35 -45
- package/dist/Sandwich/index.d.ts.map +1 -1
- package/dist/Sandwich/index.js +6 -5
- package/dist/SourceView/index.d.ts.map +1 -1
- package/dist/SourceView/index.js +6 -4
- package/dist/SourceView/useSelectedLineRange.d.ts.map +1 -1
- package/dist/SourceView/useSelectedLineRange.js +52 -76
- package/dist/Table/MoreDropdown.d.ts.map +1 -1
- package/dist/Table/MoreDropdown.js +42 -53
- package/dist/Table/TableContextMenu.d.ts.map +1 -1
- package/dist/Table/TableContextMenu.js +15 -19
- package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -1
- package/dist/Table/hooks/useTableConfiguration.js +107 -115
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +16 -16
- package/dist/TopTable/index.d.ts.map +1 -1
- package/dist/TopTable/index.js +112 -127
- package/dist/hooks/urlParsers.d.ts +18 -0
- package/dist/hooks/urlParsers.d.ts.map +1 -0
- package/dist/hooks/urlParsers.js +44 -0
- package/dist/hooks/useColorBy.d.ts +5 -0
- package/dist/hooks/useColorBy.d.ts.map +1 -0
- package/dist/hooks/useColorBy.js +63 -0
- package/dist/hooks/useCompareModeMeta.d.ts.map +1 -1
- package/dist/hooks/useCompareModeMeta.js +94 -138
- package/dist/hooks/useDashboardItems.d.ts +5 -0
- package/dist/hooks/useDashboardItems.d.ts.map +1 -0
- package/dist/hooks/useDashboardItems.js +68 -0
- package/dist/hooks/useQueryState.d.ts +4 -4
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +127 -122
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -12
- package/dist/useSumBy.d.ts +1 -1
- package/dist/useSumBy.d.ts.map +1 -1
- package/dist/useSumBy.js +2 -2
- package/package.json +4 -3
- package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +11 -13
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +11 -9
- package/src/ProfileFlameChart/SamplesStrips/index.tsx +2 -2
- package/src/ProfileFlameChart/index.tsx +21 -28
- package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +10 -9
- package/src/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.tsx +5 -3
- package/src/ProfileFlameGraph/index.tsx +6 -9
- package/src/ProfileMetricsGraph/index.tsx +6 -8
- package/src/ProfileSelector/MetricsGraphSection.tsx +5 -10
- package/src/ProfileSelector/index.tsx +33 -33
- package/src/ProfileSelector/useAutoQuerySelector.ts +64 -42
- package/src/ProfileView/components/ActionButtons/SortByDropdown.tsx +10 -6
- package/src/ProfileView/components/ColorStackLegend.tsx +2 -4
- package/src/ProfileView/components/InvertCallStack/index.tsx +5 -4
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.tsx +94 -192
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +21 -21
- package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +24 -25
- package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +4 -5
- package/src/ProfileView/components/Toolbars/index.tsx +3 -3
- package/src/ProfileView/components/ViewSelector/index.tsx +9 -16
- package/src/ProfileView/context/DashboardContext.tsx +6 -6
- package/src/ProfileView/hooks/useResetFlameGraphState.ts +6 -4
- package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +24 -26
- package/src/ProfileView/hooks/useResetStateOnSeriesChange.ts +16 -8
- package/src/ProfileView/hooks/useVisualizationState.ts +61 -69
- package/src/ProfileViewWithData.tsx +29 -35
- package/src/Sandwich/index.tsx +4 -3
- package/src/SourceView/index.tsx +4 -2
- package/src/SourceView/useSelectedLineRange.ts +34 -19
- package/src/Table/MoreDropdown.tsx +9 -11
- package/src/Table/TableContextMenu.tsx +10 -13
- package/src/Table/hooks/useTableConfiguration.tsx +3 -4
- package/src/Table/index.tsx +12 -21
- package/src/TopTable/index.tsx +3 -4
- package/src/hooks/urlParsers.ts +38 -0
- package/src/hooks/useColorBy.ts +42 -0
- package/src/hooks/useCompareModeMeta.ts +61 -91
- package/src/hooks/useDashboardItems.ts +46 -0
- package/src/hooks/useQueryState.test.tsx +275 -345
- package/src/hooks/useQueryState.ts +153 -120
- package/src/index.tsx +16 -15
- package/src/useSumBy.ts +3 -3
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
import {useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {createColumnHelper, type ColumnDef} from '@tanstack/table-core';
|
|
17
|
+
import {useQueryState} from 'nuqs';
|
|
17
18
|
|
|
18
|
-
import {useURLState} from '@parca/components';
|
|
19
19
|
import {ProfileType} from '@parca/parser';
|
|
20
20
|
import {valueFormatter} from '@parca/utilities';
|
|
21
21
|
|
|
22
22
|
import {Row} from '../../../Table';
|
|
23
23
|
import ColumnsVisibility from '../../../Table/ColumnsVisibility';
|
|
24
24
|
import {ColumnName, addPlusSign, getRatioString} from '../../../Table/utils/functions';
|
|
25
|
+
import {tableColumnsParser} from '../../../hooks/urlParsers';
|
|
25
26
|
import {useProfileViewContext} from '../../context/ProfileViewContext';
|
|
26
27
|
|
|
27
28
|
interface Props {
|
|
@@ -32,9 +33,7 @@ interface Props {
|
|
|
32
33
|
|
|
33
34
|
const TableColumnsDropdown = ({profileType, total, filtered}: Props): JSX.Element => {
|
|
34
35
|
const {compareMode} = useProfileViewContext();
|
|
35
|
-
const [tableColumns, setTableColumns] =
|
|
36
|
-
alwaysReturnArray: true,
|
|
37
|
-
});
|
|
36
|
+
const [tableColumns, setTableColumns] = useQueryState('table_columns', tableColumnsParser);
|
|
38
37
|
|
|
39
38
|
const columnHelper = createColumnHelper<Row>();
|
|
40
39
|
|
|
@@ -190,7 +189,7 @@ const TableColumnsDropdown = ({profileType, total, filtered}: Props): JSX.Elemen
|
|
|
190
189
|
const newTableColumns = (Object.keys(updatedColumns) as ColumnName[]).filter(
|
|
191
190
|
col => updatedColumns[col]
|
|
192
191
|
);
|
|
193
|
-
setTableColumns(newTableColumns);
|
|
192
|
+
void setTableColumns(newTableColumns);
|
|
194
193
|
};
|
|
195
194
|
|
|
196
195
|
return (
|
|
@@ -50,7 +50,7 @@ export interface VisualisationToolbarProps {
|
|
|
50
50
|
flamechartDimension: string[];
|
|
51
51
|
setFlamechartDimension: (labels: string[]) => void;
|
|
52
52
|
showVisualizationSelector?: boolean;
|
|
53
|
-
sandwichFunctionName
|
|
53
|
+
sandwichFunctionName: string | null;
|
|
54
54
|
alignFunctionName: string;
|
|
55
55
|
setAlignFunctionName: (align: string) => void;
|
|
56
56
|
colorBy: string;
|
|
@@ -75,7 +75,7 @@ export interface FlameGraphToolbarProps {
|
|
|
75
75
|
|
|
76
76
|
export interface SandwichFlameGraphToolbarProps {
|
|
77
77
|
resetSandwichFunctionName: () => void;
|
|
78
|
-
sandwichFunctionName
|
|
78
|
+
sandwichFunctionName: string | null;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
export const TableToolbar: FC<TableToolbarProps> = ({profileType, total, filtered}) => {
|
|
@@ -120,7 +120,7 @@ export const SandwichFlameGraphToolbar: FC<SandwichFlameGraphToolbarProps> = ({
|
|
|
120
120
|
onClick={() => resetSandwichFunctionName()}
|
|
121
121
|
className="w-auto"
|
|
122
122
|
variant="neutral"
|
|
123
|
-
disabled={sandwichFunctionName
|
|
123
|
+
disabled={sandwichFunctionName == null || sandwichFunctionName.length === 0}
|
|
124
124
|
>
|
|
125
125
|
Reset view
|
|
126
126
|
</Button>
|
|
@@ -13,9 +13,13 @@
|
|
|
13
13
|
|
|
14
14
|
import {ReactNode} from 'react';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {useQueryState} from 'nuqs';
|
|
17
|
+
|
|
18
|
+
import {useParcaContext} from '@parca/components';
|
|
17
19
|
|
|
18
20
|
import {ProfileSource} from '../../../ProfileSource';
|
|
21
|
+
import {stringParam} from '../../../hooks/urlParsers';
|
|
22
|
+
import {useDashboardItems} from '../../../hooks/useDashboardItems';
|
|
19
23
|
import Dropdown, {DropdownElement, InnerAction} from './Dropdown';
|
|
20
24
|
|
|
21
25
|
interface Props {
|
|
@@ -23,15 +27,9 @@ interface Props {
|
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
const ViewSelector = ({profileSource}: Props): JSX.Element => {
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
{
|
|
29
|
-
alwaysReturnArray: true,
|
|
30
|
-
}
|
|
31
|
-
);
|
|
32
|
-
const [, setSandwichFunctionName] = useURLState<string | undefined>('sandwich_function_name');
|
|
30
|
+
const {dashboardItems, setDashboardItems} = useDashboardItems();
|
|
31
|
+
const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
|
|
33
32
|
const {enableSourcesView, enableSandwichView} = useParcaContext();
|
|
34
|
-
const batchUpdates = useURLStateBatch();
|
|
35
33
|
|
|
36
34
|
const allItems: Array<{
|
|
37
35
|
key: string;
|
|
@@ -129,14 +127,9 @@ const ViewSelector = ({profileSource}: Props): JSX.Element => {
|
|
|
129
127
|
} else {
|
|
130
128
|
const newDashboardItems = dashboardItems.filter(v => v !== item.key);
|
|
131
129
|
|
|
132
|
-
|
|
130
|
+
setDashboardItems(newDashboardItems);
|
|
133
131
|
if (item.key === 'sandwich') {
|
|
134
|
-
|
|
135
|
-
setDashboardItems(newDashboardItems);
|
|
136
|
-
setSandwichFunctionName(undefined);
|
|
137
|
-
});
|
|
138
|
-
} else {
|
|
139
|
-
setDashboardItems(newDashboardItems);
|
|
132
|
+
void setSandwichFunctionName(null);
|
|
140
133
|
}
|
|
141
134
|
}
|
|
142
135
|
},
|
|
@@ -13,8 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
import {FC, PropsWithChildren, createContext, useContext} from 'react';
|
|
15
15
|
|
|
16
|
-
import {
|
|
16
|
+
import {useQueryState} from 'nuqs';
|
|
17
17
|
|
|
18
|
+
import {stringParam} from '../../hooks/urlParsers';
|
|
19
|
+
import {useDashboardItems} from '../../hooks/useDashboardItems';
|
|
18
20
|
import {VisualizationType} from '../types/visualization';
|
|
19
21
|
|
|
20
22
|
interface DashboardContextType {
|
|
@@ -27,10 +29,8 @@ interface DashboardContextType {
|
|
|
27
29
|
const DashboardContext = createContext<DashboardContextType | undefined>(undefined);
|
|
28
30
|
|
|
29
31
|
export const DashboardProvider: FC<PropsWithChildren> = ({children}) => {
|
|
30
|
-
const
|
|
31
|
-
|
|
32
|
-
});
|
|
33
|
-
const [, setSandwichFunctionName] = useURLState<string | undefined>('sandwich_function_name');
|
|
32
|
+
const {dashboardItems, setDashboardItems} = useDashboardItems();
|
|
33
|
+
const [, setSandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
|
|
34
34
|
|
|
35
35
|
const handleClosePanel = (visualizationType: VisualizationType): void => {
|
|
36
36
|
const newDashboardItems = dashboardItems.filter(item => item !== visualizationType);
|
|
@@ -38,7 +38,7 @@ export const DashboardProvider: FC<PropsWithChildren> = ({children}) => {
|
|
|
38
38
|
|
|
39
39
|
// Reset sandwich function name when closing sandwich panel
|
|
40
40
|
if (visualizationType === 'sandwich') {
|
|
41
|
-
setSandwichFunctionName(
|
|
41
|
+
void setSandwichFunctionName(null);
|
|
42
42
|
}
|
|
43
43
|
};
|
|
44
44
|
|
|
@@ -11,17 +11,19 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import {useQueryState} from 'nuqs';
|
|
15
|
+
|
|
16
|
+
import {stringParam} from '../../hooks/urlParsers';
|
|
15
17
|
|
|
16
18
|
export const useResetFlameGraphState = (): (() => void) => {
|
|
17
|
-
const [val, setCurPath] =
|
|
19
|
+
const [val, setCurPath] = useQueryState('cur_path', stringParam);
|
|
18
20
|
|
|
19
21
|
return () => {
|
|
20
22
|
setTimeout(() => {
|
|
21
|
-
if (val ===
|
|
23
|
+
if (val === null) {
|
|
22
24
|
return;
|
|
23
25
|
}
|
|
24
|
-
setCurPath(
|
|
26
|
+
void setCurPath(null);
|
|
25
27
|
});
|
|
26
28
|
};
|
|
27
29
|
};
|
|
@@ -11,39 +11,37 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import {useQueryStates} from 'nuqs';
|
|
15
15
|
|
|
16
|
+
import {stringParam} from '../../hooks/urlParsers';
|
|
16
17
|
import {useProfileFilters} from '../components/ProfileFilters/useProfileFilters';
|
|
17
18
|
|
|
18
19
|
export const useResetStateOnProfileTypeChange = (): (() => void) => {
|
|
19
|
-
const [
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
const [state, setState] = useQueryStates(
|
|
21
|
+
{
|
|
22
|
+
group_by: stringParam,
|
|
23
|
+
cur_path: stringParam,
|
|
24
|
+
sum_by_a: stringParam,
|
|
25
|
+
sum_by_b: stringParam,
|
|
26
|
+
sandwich_function_name: stringParam,
|
|
27
|
+
},
|
|
28
|
+
{history: 'replace'}
|
|
29
|
+
);
|
|
23
30
|
const {resetFilters} = useProfileFilters();
|
|
24
|
-
const [sandwichFunctionName, setSandwichFunctionName] = useURLState('sandwich_function_name');
|
|
25
|
-
const batchUpdates = useURLStateBatch();
|
|
26
31
|
|
|
27
32
|
return () => {
|
|
28
|
-
//
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
if (sandwichFunctionName !== undefined) {
|
|
37
|
-
setSandwichFunctionName(undefined);
|
|
38
|
-
}
|
|
39
|
-
if (sumByA !== undefined) {
|
|
40
|
-
setSumByA(undefined);
|
|
41
|
-
}
|
|
42
|
-
if (sumByB !== undefined) {
|
|
43
|
-
setSumByB(undefined);
|
|
44
|
-
}
|
|
33
|
+
// Atomic reset: clear all params in single URL update
|
|
34
|
+
const updates: Record<string, null> = {};
|
|
35
|
+
if (state.group_by !== null) updates.group_by = null;
|
|
36
|
+
if (state.cur_path !== null) updates.cur_path = null;
|
|
37
|
+
if (state.sandwich_function_name !== null) updates.sandwich_function_name = null;
|
|
38
|
+
if (state.sum_by_a !== null) updates.sum_by_a = null;
|
|
39
|
+
if (state.sum_by_b !== null) updates.sum_by_b = null;
|
|
45
40
|
|
|
46
|
-
|
|
47
|
-
|
|
41
|
+
if (Object.keys(updates).length > 0) {
|
|
42
|
+
void setState(updates);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
resetFilters();
|
|
48
46
|
};
|
|
49
47
|
};
|
|
@@ -11,19 +11,27 @@
|
|
|
11
11
|
// See the License for the specific language governing permissions and
|
|
12
12
|
// limitations under the License.
|
|
13
13
|
|
|
14
|
-
import {
|
|
14
|
+
import {useQueryStates} from 'nuqs';
|
|
15
|
+
|
|
16
|
+
import {stringParam} from '../../hooks/urlParsers';
|
|
15
17
|
|
|
16
18
|
export const useResetStateOnSeriesChange = (): (() => void) => {
|
|
17
|
-
const [
|
|
18
|
-
|
|
19
|
+
const [state, setState] = useQueryStates(
|
|
20
|
+
{
|
|
21
|
+
cur_path: stringParam,
|
|
22
|
+
sandwich_function_name: stringParam,
|
|
23
|
+
},
|
|
24
|
+
{history: 'replace'}
|
|
25
|
+
);
|
|
19
26
|
|
|
20
27
|
return () => {
|
|
21
28
|
setTimeout(() => {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
const updates: Record<string, null> = {};
|
|
30
|
+
if (state.cur_path !== null) updates.cur_path = null;
|
|
31
|
+
if (state.sandwich_function_name !== null) updates.sandwich_function_name = null;
|
|
32
|
+
|
|
33
|
+
if (Object.keys(updates).length > 0) {
|
|
34
|
+
void setState(updates);
|
|
27
35
|
}
|
|
28
36
|
});
|
|
29
37
|
};
|
|
@@ -13,13 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import {useCallback, useMemo} from 'react';
|
|
15
15
|
|
|
16
|
-
import {
|
|
17
|
-
|
|
18
|
-
JSONSerializer,
|
|
19
|
-
useURLState,
|
|
20
|
-
useURLStateBatch,
|
|
21
|
-
useURLStateCustom,
|
|
22
|
-
} from '@parca/components';
|
|
16
|
+
import {useQueryState} from 'nuqs';
|
|
17
|
+
|
|
23
18
|
import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
|
|
24
19
|
|
|
25
20
|
import {
|
|
@@ -30,12 +25,19 @@ import {
|
|
|
30
25
|
FIELD_MAPPING_FILE,
|
|
31
26
|
} from '../../ProfileFlameGraph/FlameGraphArrow';
|
|
32
27
|
import {CurrentPathFrame} from '../../ProfileFlameGraph/FlameGraphArrow/utils';
|
|
28
|
+
import {
|
|
29
|
+
flamechartDimensionParser,
|
|
30
|
+
groupByParser,
|
|
31
|
+
jsonParser,
|
|
32
|
+
stringParam,
|
|
33
|
+
} from '../../hooks/urlParsers';
|
|
34
|
+
import {useColorBy} from '../../hooks/useColorBy';
|
|
33
35
|
import {useResetFlameGraphState} from './useResetFlameGraphState';
|
|
34
36
|
|
|
35
37
|
export const useVisualizationState = (): {
|
|
36
38
|
curPathArrow: CurrentPathFrame[];
|
|
37
39
|
setCurPathArrow: (path: CurrentPathFrame[]) => void;
|
|
38
|
-
colorStackLegend: string |
|
|
40
|
+
colorStackLegend: string | null;
|
|
39
41
|
colorBy: string;
|
|
40
42
|
setColorBy: (colorBy: string) => void;
|
|
41
43
|
groupBy: string[];
|
|
@@ -44,46 +46,52 @@ export const useVisualizationState = (): {
|
|
|
44
46
|
setGroupByLabels: (labels: string[]) => void;
|
|
45
47
|
flamechartDimension: string[];
|
|
46
48
|
setFlamechartDimension: (labels: string[]) => void;
|
|
47
|
-
sandwichFunctionName: string |
|
|
48
|
-
setSandwichFunctionName: (sandwichFunctionName: string |
|
|
49
|
+
sandwichFunctionName: string | null;
|
|
50
|
+
setSandwichFunctionName: (sandwichFunctionName: string | null) => void;
|
|
49
51
|
resetSandwichFunctionName: () => void;
|
|
50
52
|
alignFunctionName: string;
|
|
51
53
|
setAlignFunctionName: (align: string) => void;
|
|
52
54
|
} => {
|
|
53
|
-
const [colorByPreference, setColorByPreference] = useUserPreference<string>(
|
|
54
|
-
USER_PREFERENCES.COLOR_BY.key
|
|
55
|
-
);
|
|
56
55
|
const [alignFunctionNamePreference, setAlignFunctionNamePreference] = useUserPreference<string>(
|
|
57
56
|
USER_PREFERENCES.ALIGN_FUNCTION_NAME.key
|
|
58
57
|
);
|
|
59
58
|
|
|
60
|
-
const [curPathArrow,
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
});
|
|
72
|
-
const [
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
const
|
|
77
|
-
|
|
59
|
+
const [curPathArrow, setRawCurPathArrow] = useQueryState(
|
|
60
|
+
'cur_path',
|
|
61
|
+
jsonParser<CurrentPathFrame[]>().withDefault([])
|
|
62
|
+
);
|
|
63
|
+
const setCurPathArrow = useCallback(
|
|
64
|
+
(path: CurrentPathFrame[]) => {
|
|
65
|
+
void setRawCurPathArrow(path);
|
|
66
|
+
},
|
|
67
|
+
[setRawCurPathArrow]
|
|
68
|
+
);
|
|
69
|
+
const [colorStackLegend] = useQueryState('color_stack_legend', stringParam);
|
|
70
|
+
const {colorBy, setColorBy} = useColorBy();
|
|
71
|
+
const [alignFunctionNameRaw, setStoreAlignFunctionName] = useQueryState(
|
|
72
|
+
'align_function_name',
|
|
73
|
+
stringParam
|
|
74
|
+
);
|
|
75
|
+
const alignFunctionName = alignFunctionNameRaw ?? alignFunctionNamePreference ?? 'left';
|
|
76
|
+
const [groupBy, setStoreGroupBy] = useQueryState(
|
|
77
|
+
'group_by',
|
|
78
|
+
groupByParser.withDefault([FIELD_FUNCTION_NAME])
|
|
79
|
+
);
|
|
80
|
+
const [sandwichFunctionName, setRawSandwichFunctionName] = useQueryState(
|
|
81
|
+
'sandwich_function_name',
|
|
82
|
+
stringParam
|
|
78
83
|
);
|
|
79
|
-
const
|
|
84
|
+
const setSandwichFunctionName = useCallback(
|
|
85
|
+
(name: string | null) => {
|
|
86
|
+
void setRawSandwichFunctionName(name);
|
|
87
|
+
},
|
|
88
|
+
[setRawSandwichFunctionName]
|
|
89
|
+
);
|
|
90
|
+
const [flamechartDimension, setStoreFlamechartDimension] = useQueryState(
|
|
80
91
|
'flamechart_dimension',
|
|
81
|
-
|
|
82
|
-
alwaysReturnArray: true,
|
|
83
|
-
}
|
|
92
|
+
flamechartDimensionParser.withDefault([])
|
|
84
93
|
);
|
|
85
94
|
const resetFlameGraphState = useResetFlameGraphState();
|
|
86
|
-
const batchUpdates = useURLStateBatch();
|
|
87
95
|
|
|
88
96
|
const levelsOfProfiling = useMemo(
|
|
89
97
|
() => [
|
|
@@ -97,62 +105,46 @@ export const useVisualizationState = (): {
|
|
|
97
105
|
|
|
98
106
|
const setGroupBy = useCallback(
|
|
99
107
|
(keys: string[]): void => {
|
|
100
|
-
setStoreGroupBy(keys);
|
|
108
|
+
void setStoreGroupBy(keys);
|
|
101
109
|
},
|
|
102
110
|
[setStoreGroupBy]
|
|
103
111
|
);
|
|
104
112
|
|
|
105
113
|
const toggleGroupBy = useCallback(
|
|
106
114
|
(key: string): void => {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
resetFlameGraphState();
|
|
117
|
-
});
|
|
115
|
+
if (groupBy.includes(key)) {
|
|
116
|
+
setGroupBy(groupBy.filter(v => v !== key));
|
|
117
|
+
} else {
|
|
118
|
+
const filteredGroupBy = groupBy.filter(item => !levelsOfProfiling.includes(item));
|
|
119
|
+
setGroupBy([...filteredGroupBy, key]);
|
|
120
|
+
}
|
|
121
|
+
resetFlameGraphState();
|
|
118
122
|
},
|
|
119
|
-
[groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState
|
|
123
|
+
[groupBy, setGroupBy, levelsOfProfiling, resetFlameGraphState]
|
|
120
124
|
);
|
|
121
125
|
|
|
122
126
|
const setGroupByLabels = useCallback(
|
|
123
127
|
(labels: string[]): void => {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
|
|
127
|
-
|
|
128
|
-
resetFlameGraphState();
|
|
129
|
-
});
|
|
128
|
+
setGroupBy(groupBy.filter(l => !l.startsWith(`${FIELD_LABELS}.`)).concat(labels));
|
|
129
|
+
resetFlameGraphState();
|
|
130
130
|
},
|
|
131
|
-
[groupBy, setGroupBy, resetFlameGraphState
|
|
131
|
+
[groupBy, setGroupBy, resetFlameGraphState]
|
|
132
132
|
);
|
|
133
133
|
|
|
134
134
|
const setFlamechartDimension = useCallback(
|
|
135
135
|
(labels: string[]): void => {
|
|
136
|
-
setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
|
|
136
|
+
void setStoreFlamechartDimension(labels.filter(l => l.startsWith(`${FIELD_LABELS}.`)));
|
|
137
137
|
},
|
|
138
138
|
[setStoreFlamechartDimension]
|
|
139
139
|
);
|
|
140
140
|
|
|
141
141
|
const resetSandwichFunctionName = useCallback((): void => {
|
|
142
|
-
setSandwichFunctionName(
|
|
142
|
+
setSandwichFunctionName(null);
|
|
143
143
|
}, [setSandwichFunctionName]);
|
|
144
144
|
|
|
145
|
-
const setColorBy = useCallback(
|
|
146
|
-
(value: string): void => {
|
|
147
|
-
setStoreColorBy(value);
|
|
148
|
-
setColorByPreference(value);
|
|
149
|
-
},
|
|
150
|
-
[setStoreColorBy, setColorByPreference]
|
|
151
|
-
);
|
|
152
|
-
|
|
153
145
|
const setAlignFunctionName = useCallback(
|
|
154
146
|
(value: string): void => {
|
|
155
|
-
setStoreAlignFunctionName(value);
|
|
147
|
+
void setStoreAlignFunctionName(value);
|
|
156
148
|
setAlignFunctionNamePreference(value);
|
|
157
149
|
},
|
|
158
150
|
[setStoreAlignFunctionName, setAlignFunctionNamePreference]
|
|
@@ -162,7 +154,7 @@ export const useVisualizationState = (): {
|
|
|
162
154
|
curPathArrow,
|
|
163
155
|
setCurPathArrow,
|
|
164
156
|
colorStackLegend,
|
|
165
|
-
colorBy
|
|
157
|
+
colorBy,
|
|
166
158
|
setColorBy,
|
|
167
159
|
groupBy,
|
|
168
160
|
setGroupBy,
|
|
@@ -173,7 +165,7 @@ export const useVisualizationState = (): {
|
|
|
173
165
|
sandwichFunctionName,
|
|
174
166
|
setSandwichFunctionName,
|
|
175
167
|
resetSandwichFunctionName,
|
|
176
|
-
alignFunctionName
|
|
168
|
+
alignFunctionName,
|
|
177
169
|
setAlignFunctionName,
|
|
178
170
|
};
|
|
179
171
|
};
|
|
@@ -13,15 +13,10 @@
|
|
|
13
13
|
|
|
14
14
|
import {useEffect, useMemo, useState} from 'react';
|
|
15
15
|
|
|
16
|
+
import {useQueryState} from 'nuqs';
|
|
17
|
+
|
|
16
18
|
import {QueryRequest_ReportType, QueryServiceClient} from '@parca/client';
|
|
17
|
-
import {
|
|
18
|
-
NumberParser,
|
|
19
|
-
NumberSerializer,
|
|
20
|
-
useGrpcMetadata,
|
|
21
|
-
useParcaContext,
|
|
22
|
-
useURLState,
|
|
23
|
-
useURLStateCustom,
|
|
24
|
-
} from '@parca/components';
|
|
19
|
+
import {useGrpcMetadata, useParcaContext} from '@parca/components';
|
|
25
20
|
import {saveAsBlob} from '@parca/utilities';
|
|
26
21
|
|
|
27
22
|
import {validateFlameChartQuery} from './ProfileFlameGraph';
|
|
@@ -35,6 +30,14 @@ import {MergedProfileSource, ProfileSource} from './ProfileSource';
|
|
|
35
30
|
import {ProfileView} from './ProfileView';
|
|
36
31
|
import {useProfileFilters} from './ProfileView/components/ProfileFilters/useProfileFilters';
|
|
37
32
|
import type {SamplesSeries} from './ProfileView/types/visualization';
|
|
33
|
+
import {
|
|
34
|
+
flamechartDimensionParser,
|
|
35
|
+
groupByParser,
|
|
36
|
+
intParam,
|
|
37
|
+
invertCallStackParser,
|
|
38
|
+
stringParam,
|
|
39
|
+
} from './hooks/urlParsers';
|
|
40
|
+
import {useDashboardItems} from './hooks/useDashboardItems';
|
|
38
41
|
import {useQuery} from './useQuery';
|
|
39
42
|
import {downloadPprof} from './utils';
|
|
40
43
|
|
|
@@ -53,22 +56,14 @@ export const ProfileViewWithData = ({
|
|
|
53
56
|
onSwitchToFifteenMinutes,
|
|
54
57
|
}: ProfileViewWithDataProps): JSX.Element => {
|
|
55
58
|
const metadata = useGrpcMetadata();
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
const [
|
|
60
|
-
const [
|
|
61
|
-
const [
|
|
62
|
-
defaultValue: [FIELD_FUNCTION_NAME],
|
|
63
|
-
alwaysReturnArray: true,
|
|
64
|
-
});
|
|
65
|
-
const [sandwichFunctionName] = useURLState<string | undefined>('sandwich_function_name');
|
|
66
|
-
const [flamechartDimension] = useURLState<string[]>('flamechart_dimension', {
|
|
67
|
-
alwaysReturnArray: true,
|
|
68
|
-
});
|
|
59
|
+
const {dashboardItems, setDashboardItems} = useDashboardItems();
|
|
60
|
+
const [sourceBuildID] = useQueryState('source_buildid', stringParam);
|
|
61
|
+
const [sourceFilename] = useQueryState('source_filename', stringParam);
|
|
62
|
+
const [groupBy] = useQueryState('group_by', groupByParser.withDefault([FIELD_FUNCTION_NAME]));
|
|
63
|
+
const [sandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
|
|
64
|
+
const [flamechartDimension] = useQueryState('flamechart_dimension', flamechartDimensionParser);
|
|
69
65
|
|
|
70
|
-
const [
|
|
71
|
-
const invertCallStack = invertStack === 'true';
|
|
66
|
+
const [invertCallStack] = useQueryState('invert_call_stack', invertCallStackParser);
|
|
72
67
|
|
|
73
68
|
const [pprofDownloading, setPprofDownloading] = useState<boolean>(false);
|
|
74
69
|
|
|
@@ -110,7 +105,7 @@ export const ProfileViewWithData = ({
|
|
|
110
105
|
skip: !dashboardItems.includes('flamegraph'),
|
|
111
106
|
nodeTrimThreshold,
|
|
112
107
|
groupBy,
|
|
113
|
-
invertCallStack,
|
|
108
|
+
invertCallStack: invertCallStack ?? false,
|
|
114
109
|
protoFilters,
|
|
115
110
|
});
|
|
116
111
|
|
|
@@ -134,11 +129,10 @@ export const ProfileViewWithData = ({
|
|
|
134
129
|
);
|
|
135
130
|
|
|
136
131
|
// Samples step count: 2px per data point for finer granularity in strips
|
|
137
|
-
const [samplesStepCount] =
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
});
|
|
132
|
+
const [samplesStepCount] = useQueryState(
|
|
133
|
+
'samples_step_count',
|
|
134
|
+
intParam.withDefault(getStepCountFromScreenWidth(2))
|
|
135
|
+
);
|
|
142
136
|
|
|
143
137
|
const {
|
|
144
138
|
isLoading: samplesLoading,
|
|
@@ -203,8 +197,8 @@ export const ProfileViewWithData = ({
|
|
|
203
197
|
error: sourceError,
|
|
204
198
|
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.SOURCE, {
|
|
205
199
|
skip: !dashboardItems.includes('source'),
|
|
206
|
-
sourceBuildID,
|
|
207
|
-
sourceFilename,
|
|
200
|
+
sourceBuildID: sourceBuildID ?? undefined,
|
|
201
|
+
sourceFilename: sourceFilename ?? undefined,
|
|
208
202
|
protoFilters,
|
|
209
203
|
});
|
|
210
204
|
|
|
@@ -216,8 +210,8 @@ export const ProfileViewWithData = ({
|
|
|
216
210
|
nodeTrimThreshold,
|
|
217
211
|
groupBy: [FIELD_FUNCTION_NAME],
|
|
218
212
|
invertCallStack: true,
|
|
219
|
-
sandwichByFunction: sandwichFunctionName,
|
|
220
|
-
skip: sandwichFunctionName
|
|
213
|
+
sandwichByFunction: sandwichFunctionName ?? undefined,
|
|
214
|
+
skip: sandwichFunctionName == null && !dashboardItems.includes('sandwich'),
|
|
221
215
|
protoFilters,
|
|
222
216
|
});
|
|
223
217
|
|
|
@@ -229,8 +223,8 @@ export const ProfileViewWithData = ({
|
|
|
229
223
|
nodeTrimThreshold,
|
|
230
224
|
groupBy: [FIELD_FUNCTION_NAME],
|
|
231
225
|
invertCallStack: false,
|
|
232
|
-
sandwichByFunction: sandwichFunctionName,
|
|
233
|
-
skip: sandwichFunctionName
|
|
226
|
+
sandwichByFunction: sandwichFunctionName ?? undefined,
|
|
227
|
+
skip: sandwichFunctionName == null && !dashboardItems.includes('sandwich'),
|
|
234
228
|
protoFilters,
|
|
235
229
|
});
|
|
236
230
|
|
package/src/Sandwich/index.tsx
CHANGED
|
@@ -14,14 +14,15 @@
|
|
|
14
14
|
import React, {useRef, useState} from 'react';
|
|
15
15
|
|
|
16
16
|
import {AnimatePresence, motion} from 'framer-motion';
|
|
17
|
+
import {useQueryState} from 'nuqs';
|
|
17
18
|
|
|
18
|
-
import {useURLState} from '@parca/components';
|
|
19
19
|
import {TEST_IDS, testId} from '@parca/test-utils';
|
|
20
20
|
|
|
21
21
|
import {ProfileSource} from '../ProfileSource';
|
|
22
22
|
import {useDashboard} from '../ProfileView/context/DashboardContext';
|
|
23
23
|
import {useVisualizationState} from '../ProfileView/hooks/useVisualizationState';
|
|
24
24
|
import {SandwichData} from '../ProfileView/types/visualization';
|
|
25
|
+
import {stringParam} from '../hooks/urlParsers';
|
|
25
26
|
import {CalleesSection} from './components/CalleesSection';
|
|
26
27
|
import {CallersSection} from './components/CallersSection';
|
|
27
28
|
|
|
@@ -35,7 +36,7 @@ const Sandwich = React.memo(function Sandwich({
|
|
|
35
36
|
profileSource,
|
|
36
37
|
}: Props): React.JSX.Element {
|
|
37
38
|
const {dashboardItems} = useDashboard();
|
|
38
|
-
const [sandwichFunctionName] =
|
|
39
|
+
const [sandwichFunctionName] = useQueryState('sandwich_function_name', stringParam);
|
|
39
40
|
|
|
40
41
|
const callersRef = React.useRef<HTMLDivElement | null>(null);
|
|
41
42
|
const calleesRef = React.useRef<HTMLDivElement | null>(null);
|
|
@@ -57,7 +58,7 @@ const Sandwich = React.memo(function Sandwich({
|
|
|
57
58
|
transition={{duration: 0.5}}
|
|
58
59
|
>
|
|
59
60
|
<div className="relative flex flex-row">
|
|
60
|
-
{sandwichFunctionName
|
|
61
|
+
{sandwichFunctionName != null ? (
|
|
61
62
|
<div className="w-full flex flex-col" ref={callersCalleesContainerRef}>
|
|
62
63
|
<CallersSection
|
|
63
64
|
callersRef={callersRef}
|
package/src/SourceView/index.tsx
CHANGED
|
@@ -15,12 +15,14 @@ import React, {useCallback, useEffect, useMemo} from 'react';
|
|
|
15
15
|
|
|
16
16
|
import {tableFromIPC} from '@uwdata/flechette';
|
|
17
17
|
import {AnimatePresence, motion} from 'framer-motion';
|
|
18
|
+
import {useQueryState} from 'nuqs';
|
|
18
19
|
import {Item, Menu, useContextMenu} from 'react-contexify';
|
|
19
20
|
|
|
20
21
|
import {Source} from '@parca/client';
|
|
21
|
-
import {SourceSkeleton, useParcaContext,
|
|
22
|
+
import {SourceSkeleton, useParcaContext, type ProfileData} from '@parca/components';
|
|
22
23
|
|
|
23
24
|
import {ExpandOnHover} from '../GraphTooltipArrow/ExpandOnHoverValue';
|
|
25
|
+
import {stringParam} from '../hooks/urlParsers';
|
|
24
26
|
import {alignedUint8Array, truncateStringReverse} from '../utils';
|
|
25
27
|
import {Highlighter, profileAwareRenderer, type LineDataLookup} from './Highlighter';
|
|
26
28
|
import useLineRange from './useSelectedLineRange';
|
|
@@ -42,7 +44,7 @@ export const SourceView = React.memo(function SourceView({
|
|
|
42
44
|
filtered,
|
|
43
45
|
setActionButtons,
|
|
44
46
|
}: SourceViewProps): JSX.Element {
|
|
45
|
-
const [sourceFileName] =
|
|
47
|
+
const [sourceFileName] = useQueryState('source_filename', stringParam);
|
|
46
48
|
const {isDarkMode, sourceViewContextMenuItems = []} = useParcaContext();
|
|
47
49
|
|
|
48
50
|
const sourceCode = useMemo(() => {
|