@parca/profile 0.16.449 → 0.16.451

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 (158) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +1 -1
  3. package/dist/MetricsGraphStrips/AreaGraph/index.d.ts +1 -1
  4. package/dist/MetricsGraphStrips/AreaGraph/index.d.ts.map +1 -1
  5. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.d.ts +2 -1
  6. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.d.ts.map +1 -1
  7. package/dist/MetricsGraphStrips/MetricsGraphStrips.stories.js +8 -1
  8. package/dist/MetricsGraphStrips/index.d.ts +2 -1
  9. package/dist/MetricsGraphStrips/index.d.ts.map +1 -1
  10. package/dist/MetricsGraphStrips/index.js +13 -3
  11. package/dist/ProfileIcicleGraph/IcicleGraph/index.js +1 -1
  12. package/dist/ProfileIcicleGraph/IcicleGraphArrow/index.js +2 -2
  13. package/dist/ProfileIcicleGraph/index.js +2 -2
  14. package/dist/ProfileView/components/ActionButtons/GroupByDropdown.d.ts.map +1 -0
  15. package/dist/{components → ProfileView/components}/ActionButtons/GroupByDropdown.js +1 -1
  16. package/dist/ProfileView/components/ActionButtons/SortByDropdown.d.ts.map +1 -0
  17. package/dist/{components → ProfileView/components}/ActionButtons/SortByDropdown.js +2 -2
  18. package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -0
  19. package/dist/ProfileView/{ColorStackLegend.js → components/ColorStackLegend.js} +2 -2
  20. package/dist/ProfileView/components/DashboardItems/index.d.ts +26 -0
  21. package/dist/ProfileView/components/DashboardItems/index.d.ts.map +1 -0
  22. package/dist/ProfileView/components/DashboardItems/index.js +42 -0
  23. package/dist/ProfileView/components/DashboardLayout/index.d.ts +15 -0
  24. package/dist/ProfileView/components/DashboardLayout/index.d.ts.map +1 -0
  25. package/dist/ProfileView/components/DashboardLayout/index.js +20 -0
  26. package/dist/ProfileView/components/DiffLegend.d.ts.map +1 -0
  27. package/dist/ProfileView/components/FilterByFunctionButton.d.ts.map +1 -0
  28. package/dist/ProfileView/components/ProfileHeader/index.d.ts +9 -0
  29. package/dist/ProfileView/components/ProfileHeader/index.d.ts.map +1 -0
  30. package/dist/ProfileView/components/ProfileHeader/index.js +12 -0
  31. package/dist/ProfileView/components/ShareButton/ResultBox.d.ts.map +1 -0
  32. package/dist/{components → ProfileView/components}/ShareButton/index.d.ts +1 -1
  33. package/dist/ProfileView/components/ShareButton/index.d.ts.map +1 -0
  34. package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -0
  35. package/dist/{components/VisualisationToolbar → ProfileView/components/Toolbars}/MultiLevelDropdown.js +2 -2
  36. package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -0
  37. package/dist/{components/VisualisationToolbar → ProfileView/components/Toolbars}/TableColumnsDropdown.js +4 -4
  38. package/dist/ProfileView/components/Toolbars/index.d.ts +41 -0
  39. package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -0
  40. package/dist/ProfileView/components/Toolbars/index.js +24 -0
  41. package/dist/ProfileView/components/ViewSelector/Dropdown.d.ts.map +1 -0
  42. package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -0
  43. package/dist/ProfileView/components/VisualizationContainer/index.d.ts +21 -0
  44. package/dist/ProfileView/components/VisualizationContainer/index.d.ts.map +1 -0
  45. package/dist/ProfileView/components/VisualizationContainer/index.js +8 -0
  46. package/dist/ProfileView/{VisualizationPanel.d.ts → components/VisualizationPanel.d.ts} +4 -3
  47. package/dist/ProfileView/components/VisualizationPanel.d.ts.map +1 -0
  48. package/dist/ProfileView/context/DashboardContext.d.ts +12 -0
  49. package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -0
  50. package/dist/ProfileView/context/DashboardContext.js +39 -0
  51. package/dist/ProfileView/{ProfileViewContext.d.ts → context/ProfileViewContext.d.ts} +1 -1
  52. package/dist/ProfileView/context/ProfileViewContext.d.ts.map +1 -0
  53. package/dist/ProfileView/hooks/useGraphviz.d.ts +12 -0
  54. package/dist/ProfileView/hooks/useGraphviz.d.ts.map +1 -0
  55. package/dist/ProfileView/hooks/useGraphviz.js +42 -0
  56. package/dist/ProfileView/hooks/useProfileMetadata.d.ts +17 -0
  57. package/dist/ProfileView/hooks/useProfileMetadata.d.ts.map +1 -0
  58. package/dist/ProfileView/hooks/useProfileMetadata.js +30 -0
  59. package/dist/ProfileView/hooks/useVisualizationState.d.ts +14 -0
  60. package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -0
  61. package/dist/ProfileView/hooks/useVisualizationState.js +52 -0
  62. package/dist/ProfileView/index.d.ts +2 -49
  63. package/dist/ProfileView/index.d.ts.map +1 -1
  64. package/dist/ProfileView/index.js +54 -173
  65. package/dist/ProfileView/types/visualization.d.ts +49 -0
  66. package/dist/ProfileView/types/visualization.d.ts.map +1 -0
  67. package/dist/ProfileView/types/visualization.js +13 -0
  68. package/dist/ProfileView/utils/colorUtils.d.ts +3 -0
  69. package/dist/ProfileView/utils/colorUtils.d.ts.map +1 -0
  70. package/dist/ProfileView/utils/colorUtils.js +21 -0
  71. package/dist/ProfileViewWithData.d.ts +2 -1
  72. package/dist/ProfileViewWithData.d.ts.map +1 -1
  73. package/dist/ProfileViewWithData.js +2 -2
  74. package/dist/SourceView/Highlighter.js +1 -1
  75. package/dist/Table/index.js +1 -1
  76. package/dist/TimelineGuide/index.d.ts +11 -0
  77. package/dist/TimelineGuide/index.d.ts.map +1 -0
  78. package/dist/{MetricsGraphStrips/TimelineGuide → TimelineGuide}/index.js +3 -13
  79. package/dist/TopTable/index.js +1 -1
  80. package/dist/styles.css +1 -1
  81. package/dist/utils.d.ts +1 -0
  82. package/dist/utils.d.ts.map +1 -1
  83. package/package.json +2 -2
  84. package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +1 -1
  85. package/src/MetricsGraphStrips/AreaGraph/index.tsx +2 -2
  86. package/src/MetricsGraphStrips/MetricsGraphStrips.stories.tsx +11 -2
  87. package/src/MetricsGraphStrips/index.tsx +16 -4
  88. package/src/ProfileIcicleGraph/IcicleGraph/index.tsx +1 -1
  89. package/src/ProfileIcicleGraph/IcicleGraphArrow/index.tsx +2 -2
  90. package/src/ProfileIcicleGraph/index.tsx +2 -2
  91. package/src/{components → ProfileView/components}/ActionButtons/GroupByDropdown.tsx +1 -1
  92. package/src/{components → ProfileView/components}/ActionButtons/SortByDropdown.tsx +2 -2
  93. package/src/ProfileView/{ColorStackLegend.tsx → components/ColorStackLegend.tsx} +2 -2
  94. package/src/ProfileView/components/DashboardItems/index.tsx +148 -0
  95. package/src/ProfileView/components/DashboardLayout/index.tsx +96 -0
  96. package/src/ProfileView/components/ProfileHeader/index.tsx +68 -0
  97. package/src/{components → ProfileView/components}/ShareButton/index.tsx +1 -1
  98. package/src/{components/VisualisationToolbar → ProfileView/components/Toolbars}/MultiLevelDropdown.tsx +2 -6
  99. package/src/{components/VisualisationToolbar → ProfileView/components/Toolbars}/TableColumnsDropdown.tsx +4 -4
  100. package/src/ProfileView/components/Toolbars/index.tsx +193 -0
  101. package/src/ProfileView/components/VisualizationContainer/index.tsx +68 -0
  102. package/src/ProfileView/{VisualizationPanel.tsx → components/VisualizationPanel.tsx} +5 -3
  103. package/src/ProfileView/context/DashboardContext.tsx +61 -0
  104. package/src/ProfileView/{ProfileViewContext.tsx → context/ProfileViewContext.tsx} +1 -1
  105. package/src/ProfileView/hooks/useGraphviz.ts +69 -0
  106. package/src/ProfileView/hooks/useProfileMetadata.ts +59 -0
  107. package/src/ProfileView/hooks/useVisualizationState.ts +82 -0
  108. package/src/ProfileView/index.tsx +126 -451
  109. package/src/ProfileView/types/visualization.ts +75 -0
  110. package/src/ProfileView/utils/colorUtils.ts +24 -0
  111. package/src/ProfileViewWithData.tsx +3 -0
  112. package/src/SourceView/Highlighter.tsx +1 -1
  113. package/src/Table/index.tsx +1 -1
  114. package/src/{MetricsGraphStrips/TimelineGuide → TimelineGuide}/index.tsx +7 -17
  115. package/src/TopTable/index.tsx +1 -1
  116. package/src/utils.ts +2 -0
  117. package/dist/MetricsGraphStrips/TimelineGuide/index.d.ts +0 -10
  118. package/dist/MetricsGraphStrips/TimelineGuide/index.d.ts.map +0 -1
  119. package/dist/ProfileView/ColorStackLegend.d.ts.map +0 -1
  120. package/dist/ProfileView/ProfileViewContext.d.ts.map +0 -1
  121. package/dist/ProfileView/VisualizationPanel.d.ts.map +0 -1
  122. package/dist/components/ActionButtons/GroupByDropdown.d.ts.map +0 -1
  123. package/dist/components/ActionButtons/SortByDropdown.d.ts.map +0 -1
  124. package/dist/components/DiffLegend.d.ts.map +0 -1
  125. package/dist/components/FilterByFunctionButton.d.ts.map +0 -1
  126. package/dist/components/ShareButton/ResultBox.d.ts.map +0 -1
  127. package/dist/components/ShareButton/index.d.ts.map +0 -1
  128. package/dist/components/ViewSelector/Dropdown.d.ts.map +0 -1
  129. package/dist/components/ViewSelector/index.d.ts.map +0 -1
  130. package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts.map +0 -1
  131. package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts.map +0 -1
  132. package/dist/components/VisualisationToolbar/index.d.ts +0 -37
  133. package/dist/components/VisualisationToolbar/index.d.ts.map +0 -1
  134. package/dist/components/VisualisationToolbar/index.js +0 -64
  135. package/src/components/VisualisationToolbar/index.tsx +0 -228
  136. /package/dist/{components → ProfileView/components}/ActionButtons/GroupByDropdown.d.ts +0 -0
  137. /package/dist/{components → ProfileView/components}/ActionButtons/SortByDropdown.d.ts +0 -0
  138. /package/dist/ProfileView/{ColorStackLegend.d.ts → components/ColorStackLegend.d.ts} +0 -0
  139. /package/dist/{components → ProfileView/components}/DiffLegend.d.ts +0 -0
  140. /package/dist/{components → ProfileView/components}/DiffLegend.js +0 -0
  141. /package/dist/{components → ProfileView/components}/FilterByFunctionButton.d.ts +0 -0
  142. /package/dist/{components → ProfileView/components}/FilterByFunctionButton.js +0 -0
  143. /package/dist/{components → ProfileView/components}/ShareButton/ResultBox.d.ts +0 -0
  144. /package/dist/{components → ProfileView/components}/ShareButton/ResultBox.js +0 -0
  145. /package/dist/{components → ProfileView/components}/ShareButton/index.js +0 -0
  146. /package/dist/{components/VisualisationToolbar → ProfileView/components/Toolbars}/MultiLevelDropdown.d.ts +0 -0
  147. /package/dist/{components/VisualisationToolbar → ProfileView/components/Toolbars}/TableColumnsDropdown.d.ts +0 -0
  148. /package/dist/{components → ProfileView/components}/ViewSelector/Dropdown.d.ts +0 -0
  149. /package/dist/{components → ProfileView/components}/ViewSelector/Dropdown.js +0 -0
  150. /package/dist/{components → ProfileView/components}/ViewSelector/index.d.ts +0 -0
  151. /package/dist/{components → ProfileView/components}/ViewSelector/index.js +0 -0
  152. /package/dist/ProfileView/{VisualizationPanel.js → components/VisualizationPanel.js} +0 -0
  153. /package/dist/ProfileView/{ProfileViewContext.js → context/ProfileViewContext.js} +0 -0
  154. /package/src/{components → ProfileView/components}/DiffLegend.tsx +0 -0
  155. /package/src/{components → ProfileView/components}/FilterByFunctionButton.tsx +0 -0
  156. /package/src/{components → ProfileView/components}/ShareButton/ResultBox.tsx +0 -0
  157. /package/src/{components → ProfileView/components}/ViewSelector/Dropdown.tsx +0 -0
  158. /package/src/{components → ProfileView/components}/ViewSelector/index.tsx +0 -0
@@ -0,0 +1,96 @@
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 {FC} from 'react';
15
+
16
+ import cx from 'classnames';
17
+ import {
18
+ DragDropContext,
19
+ Draggable,
20
+ Droppable,
21
+ type DraggableLocation,
22
+ type DropResult,
23
+ } from 'react-beautiful-dnd';
24
+
25
+ import {useDashboard} from '../../context/DashboardContext';
26
+ import {VisualizationType} from '../../types/visualization';
27
+ import {VisualizationContainer} from '../VisualizationContainer';
28
+
29
+ interface DashboardLayoutProps {
30
+ getDashboardItemByType: (props: {type: VisualizationType; isHalfScreen: boolean}) => JSX.Element;
31
+ actionButtons: {
32
+ icicle: JSX.Element;
33
+ table: JSX.Element;
34
+ };
35
+ }
36
+
37
+ export const DashboardLayout: FC<DashboardLayoutProps> = ({
38
+ getDashboardItemByType,
39
+ actionButtons,
40
+ }) => {
41
+ const {dashboardItems, setDashboardItems, isMultiPanelView} = useDashboard();
42
+
43
+ const onDragEnd = (result: DropResult): void => {
44
+ const {destination, source, draggableId} = result;
45
+
46
+ if (Boolean(destination) && destination?.index !== source.index) {
47
+ const targetItem = draggableId;
48
+ const otherItems = dashboardItems.filter(item => item !== targetItem);
49
+ const newDashboardItems =
50
+ (destination as DraggableLocation).index < source.index
51
+ ? [targetItem, ...otherItems]
52
+ : [...otherItems, targetItem];
53
+
54
+ setDashboardItems(newDashboardItems);
55
+ }
56
+ };
57
+
58
+ return (
59
+ <DragDropContext onDragEnd={onDragEnd}>
60
+ <Droppable droppableId="droppable" direction="horizontal">
61
+ {provided => (
62
+ <div
63
+ ref={provided.innerRef}
64
+ className={cx(
65
+ 'grid w-full gap-2',
66
+ isMultiPanelView ? 'grid-cols-2 mt-4' : 'grid-cols-1'
67
+ )}
68
+ {...provided.droppableProps}
69
+ >
70
+ {dashboardItems.map((dashboardItem, index) => (
71
+ <Draggable
72
+ key={dashboardItem}
73
+ draggableId={dashboardItem}
74
+ index={index}
75
+ isDragDisabled={!isMultiPanelView}
76
+ >
77
+ {(provided, snapshot) => (
78
+ <VisualizationContainer
79
+ provided={provided}
80
+ snapshot={snapshot}
81
+ dashboardItem={dashboardItem as VisualizationType}
82
+ getDashboardItemByType={getDashboardItemByType}
83
+ isMultiPanelView={isMultiPanelView}
84
+ index={index}
85
+ actionButtons={actionButtons}
86
+ />
87
+ )}
88
+ </Draggable>
89
+ ))}
90
+ {provided.placeholder}
91
+ </div>
92
+ )}
93
+ </Droppable>
94
+ </DragDropContext>
95
+ );
96
+ };
@@ -0,0 +1,68 @@
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 {FC} from 'react';
15
+
16
+ import cx from 'classnames';
17
+
18
+ interface ProfileHeaderProps {
19
+ profileSourceString?: string;
20
+ hasProfileSource: boolean;
21
+ externalMainActions?: React.ReactNode;
22
+ }
23
+
24
+ export const ProfileHeader: FC<ProfileHeaderProps> = ({
25
+ profileSourceString,
26
+ hasProfileSource,
27
+
28
+ externalMainActions,
29
+ }) => {
30
+ const headerParts = profileSourceString?.split('"') ?? [];
31
+
32
+ const showDivider =
33
+ hasProfileSource && (externalMainActions === null || externalMainActions === undefined);
34
+
35
+ return (
36
+ <>
37
+ {showDivider && (
38
+ <div className="border-t border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" />
39
+ )}
40
+ <div
41
+ className={cx(
42
+ 'flex w-full',
43
+ hasProfileSource || externalMainActions != null ? 'justify-start' : 'justify-end',
44
+ {
45
+ 'items-end mb-4': !hasProfileSource && externalMainActions != null,
46
+ 'items-center mb-2': hasProfileSource,
47
+ }
48
+ )}
49
+ >
50
+ <div>
51
+ {hasProfileSource && (
52
+ <div className="flex items-center gap-1">
53
+ <div className="text-xs font-medium">
54
+ {headerParts.length > 0 ? headerParts[0].replace(/"/g, '') : ''}
55
+ </div>
56
+ <div className="text-xs font-medium">
57
+ {headerParts.length > 1
58
+ ? headerParts[headerParts.length - 1].replace(/"/g, '')
59
+ : ''}
60
+ </div>
61
+ </div>
62
+ )}
63
+ {externalMainActions}
64
+ </div>
65
+ </div>
66
+ </>
67
+ );
68
+ };
@@ -18,7 +18,7 @@ import {Icon} from '@iconify/react';
18
18
  import {QueryRequest, QueryServiceClient} from '@parca/client';
19
19
  import {Button, Dropdown, Modal, useGrpcMetadata} from '@parca/components';
20
20
 
21
- import {ProfileSource} from '../../ProfileSource';
21
+ import {ProfileSource} from '../../../ProfileSource';
22
22
  import ResultBox from './ResultBox';
23
23
 
24
24
  interface Props {
@@ -20,12 +20,8 @@ import {useURLState} from '@parca/components';
20
20
  import {USER_PREFERENCES, useUserPreference} from '@parca/hooks';
21
21
  import {ProfileType} from '@parca/parser';
22
22
 
23
- import {
24
- FIELD_CUMULATIVE,
25
- FIELD_DIFF,
26
- FIELD_FUNCTION_NAME,
27
- } from '../../ProfileIcicleGraph/IcicleGraphArrow';
28
- import {useProfileViewContext} from '../../ProfileView/ProfileViewContext';
23
+ import {FIELD_FUNCTION_NAME} from '../../../ProfileIcicleGraph/IcicleGraphArrow';
24
+ import {useProfileViewContext} from '../../context/ProfileViewContext';
29
25
 
30
26
  interface MenuItemType {
31
27
  label: string;
@@ -19,10 +19,10 @@ import {useURLState} from '@parca/components';
19
19
  import {ProfileType} from '@parca/parser';
20
20
  import {valueFormatter} from '@parca/utilities';
21
21
 
22
- import {useProfileViewContext} from '../../ProfileView/ProfileViewContext';
23
- import {Row, isDummyRow} from '../../Table';
24
- import ColumnsVisibility from '../../Table/ColumnsVisibility';
25
- import {ColumnName, DataRow, addPlusSign, getRatioString} from '../../Table/utils/functions';
22
+ import {Row, isDummyRow} from '../../../Table';
23
+ import ColumnsVisibility from '../../../Table/ColumnsVisibility';
24
+ import {ColumnName, DataRow, addPlusSign, getRatioString} from '../../../Table/utils/functions';
25
+ import {useProfileViewContext} from '../../context/ProfileViewContext';
26
26
 
27
27
  interface Props {
28
28
  profileType?: ProfileType;
@@ -0,0 +1,193 @@
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 {FC} from 'react';
15
+
16
+ import {Icon} from '@iconify/react';
17
+
18
+ import {QueryServiceClient} from '@parca/client';
19
+ import {Button, UserPreferencesModal} from '@parca/components';
20
+ import {ProfileType} from '@parca/parser';
21
+
22
+ import {ProfileSource} from '../../../ProfileSource';
23
+ import {useDashboard} from '../../context/DashboardContext';
24
+ import GroupByDropdown from '../ActionButtons/GroupByDropdown';
25
+ import SortByDropdown from '../ActionButtons/SortByDropdown';
26
+ import FilterByFunctionButton from '../FilterByFunctionButton';
27
+ import ShareButton from '../ShareButton';
28
+ import ViewSelector from '../ViewSelector';
29
+ import MultiLevelDropdown from './MultiLevelDropdown';
30
+ import TableColumnsDropdown from './TableColumnsDropdown';
31
+
32
+ export interface VisualisationToolbarProps {
33
+ groupBy: string[];
34
+ toggleGroupBy: (key: string) => void;
35
+ hasProfileSource: boolean;
36
+ pprofdownloading?: boolean;
37
+ profileSource?: ProfileSource;
38
+ queryClient?: QueryServiceClient;
39
+ onDownloadPProf: () => void;
40
+ curPath: string[];
41
+ setNewCurPath: (path: string[]) => void;
42
+ profileType?: ProfileType;
43
+ total: bigint;
44
+ filtered: bigint;
45
+ currentSearchString?: string;
46
+ setSearchString?: (value: string) => void;
47
+ groupByLabels: string[];
48
+ preferencesModal?: boolean;
49
+ profileViewExternalSubActions?: React.ReactNode;
50
+ clearSelection: () => void;
51
+ setGroupByLabels: (labels: string[]) => void;
52
+ showVisualizationSelector?: boolean;
53
+ }
54
+
55
+ export interface TableToolbarProps {
56
+ profileType?: ProfileType;
57
+ total: bigint;
58
+ filtered: bigint;
59
+ clearSelection: () => void;
60
+ currentSearchString?: string;
61
+ }
62
+
63
+ export interface IcicleGraphToolbarProps {
64
+ curPath: string[];
65
+ setNewCurPath: (path: string[]) => void;
66
+ }
67
+
68
+ export const TableToolbar: FC<TableToolbarProps> = ({
69
+ profileType,
70
+ total,
71
+ filtered,
72
+ clearSelection,
73
+ currentSearchString,
74
+ }) => {
75
+ return (
76
+ <>
77
+ <div className="flex w-full gap-2 items-end">
78
+ <TableColumnsDropdown profileType={profileType} total={total} filtered={filtered} />
79
+ <Button
80
+ color="neutral"
81
+ onClick={clearSelection}
82
+ className="w-auto"
83
+ variant="neutral"
84
+ disabled={currentSearchString === undefined || currentSearchString.length === 0}
85
+ >
86
+ Clear selection
87
+ </Button>
88
+ </div>
89
+ </>
90
+ );
91
+ };
92
+
93
+ export const IcicleGraphToolbar: FC<IcicleGraphToolbarProps> = ({curPath, setNewCurPath}) => {
94
+ return (
95
+ <>
96
+ <div className="flex w-full gap-2 items-end">
97
+ <SortByDropdown />
98
+ <Button
99
+ variant="neutral"
100
+ className="gap-2 w-max h-fit"
101
+ onClick={() => setNewCurPath([])}
102
+ disabled={curPath.length === 0}
103
+ >
104
+ Reset graph
105
+ <Icon icon="system-uicons:reset" width={20} />
106
+ </Button>
107
+ </div>
108
+ </>
109
+ );
110
+ };
111
+
112
+ const Divider = (): JSX.Element => (
113
+ <div className="border-t mt-4 border-gray-200 dark:border-gray-700 h-[1px] w-full pb-4" />
114
+ );
115
+
116
+ export const VisualisationToolbar: FC<VisualisationToolbarProps> = ({
117
+ groupBy,
118
+ toggleGroupBy,
119
+ groupByLabels,
120
+ setGroupByLabels,
121
+ profileType,
122
+ preferencesModal,
123
+ profileSource,
124
+ queryClient,
125
+ onDownloadPProf,
126
+ pprofdownloading,
127
+ profileViewExternalSubActions,
128
+ curPath,
129
+ setNewCurPath,
130
+ total,
131
+ filtered,
132
+ currentSearchString,
133
+ clearSelection,
134
+ showVisualizationSelector = true,
135
+ }) => {
136
+ const {dashboardItems} = useDashboard();
137
+
138
+ const isTableViz = dashboardItems?.includes('table');
139
+ const isGraphViz = dashboardItems?.includes('icicle');
140
+
141
+ return (
142
+ <>
143
+ <div className="flex w-full justify-between items-end">
144
+ <div className="flex gap-3 items-end">
145
+ <>
146
+ <GroupByDropdown
147
+ groupBy={groupBy}
148
+ toggleGroupBy={toggleGroupBy}
149
+ labels={groupByLabels}
150
+ setGroupByLabels={setGroupByLabels}
151
+ />
152
+ <MultiLevelDropdown profileType={profileType} onSelect={() => {}} />
153
+ </>
154
+
155
+ <FilterByFunctionButton />
156
+
157
+ {profileViewExternalSubActions != null ? profileViewExternalSubActions : null}
158
+ </div>
159
+ <div className="flex gap-3">
160
+ {preferencesModal != null ? <UserPreferencesModal /> : null}
161
+ <ShareButton
162
+ profileSource={profileSource}
163
+ queryClient={queryClient}
164
+ queryRequest={profileSource?.QueryRequest() ?? undefined}
165
+ onDownloadPProf={onDownloadPProf}
166
+ pprofdownloading={pprofdownloading ?? false}
167
+ profileViewExternalSubActions={profileViewExternalSubActions}
168
+ />
169
+
170
+ {showVisualizationSelector ? <ViewSelector /> : null}
171
+ </div>
172
+ </div>
173
+ {isGraphViz && !isTableViz && (
174
+ <>
175
+ <Divider />
176
+ <IcicleGraphToolbar curPath={curPath} setNewCurPath={setNewCurPath} />
177
+ </>
178
+ )}
179
+ {isTableViz && !isGraphViz && (
180
+ <>
181
+ <Divider />
182
+ <TableToolbar
183
+ profileType={profileType}
184
+ total={total}
185
+ filtered={filtered}
186
+ clearSelection={clearSelection}
187
+ currentSearchString={currentSearchString}
188
+ />
189
+ </>
190
+ )}
191
+ </>
192
+ );
193
+ };
@@ -0,0 +1,68 @@
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 {FC} from 'react';
15
+
16
+ import cx from 'classnames';
17
+ import type {DraggableProvided, DraggableStateSnapshot} from 'react-beautiful-dnd';
18
+
19
+ import {useDashboard} from '../../context/DashboardContext';
20
+ import {VisualizationType} from '../../types/visualization';
21
+ import {VisualizationPanel} from '../VisualizationPanel';
22
+
23
+ interface VisualizationContainerProps {
24
+ provided: DraggableProvided;
25
+ snapshot: DraggableStateSnapshot;
26
+ dashboardItem: VisualizationType;
27
+ getDashboardItemByType: (props: {type: VisualizationType; isHalfScreen: boolean}) => JSX.Element;
28
+ isMultiPanelView: boolean;
29
+ index: number;
30
+ actionButtons: {
31
+ icicle: JSX.Element;
32
+ table: JSX.Element;
33
+ };
34
+ }
35
+
36
+ export const VisualizationContainer: FC<VisualizationContainerProps> = ({
37
+ provided,
38
+ snapshot,
39
+ dashboardItem,
40
+ getDashboardItemByType,
41
+ isMultiPanelView,
42
+ index,
43
+ actionButtons,
44
+ }) => {
45
+ const {handleClosePanel} = useDashboard();
46
+
47
+ return (
48
+ <div
49
+ ref={provided.innerRef}
50
+ {...provided.draggableProps}
51
+ className={cx(
52
+ 'w-full min-h-96',
53
+ snapshot.isDragging ? 'bg-gray-200 dark:bg-gray-500' : 'bg-white dark:bg-gray-900',
54
+ isMultiPanelView ? 'border-2 border-gray-100 dark:border-gray-700 rounded-md p-3' : ''
55
+ )}
56
+ >
57
+ <VisualizationPanel
58
+ handleClosePanel={handleClosePanel}
59
+ isMultiPanelView={isMultiPanelView}
60
+ dashboardItem={dashboardItem}
61
+ getDashboardItemByType={getDashboardItemByType}
62
+ dragHandleProps={provided.dragHandleProps}
63
+ index={index}
64
+ actionButtons={actionButtons}
65
+ />
66
+ </div>
67
+ );
68
+ };
@@ -20,13 +20,15 @@ import type {DraggableProvidedDragHandleProps} from 'react-beautiful-dnd';
20
20
  import {IconButton, useParcaContext} from '@parca/components';
21
21
  import {CloseIcon} from '@parca/icons';
22
22
 
23
+ import {VisualizationType} from '../types/visualization';
24
+
23
25
  interface Props {
24
- dashboardItem: string;
26
+ dashboardItem: VisualizationType;
25
27
  index: number;
26
28
  isMultiPanelView: boolean;
27
- handleClosePanel: (dashboardItem: string) => void;
29
+ handleClosePanel: (dashboardItem: VisualizationType) => void;
28
30
  dragHandleProps: DraggableProvidedDragHandleProps | null | undefined;
29
- getDashboardItemByType: (props: {type: string; isHalfScreen: boolean}) => JSX.Element;
31
+ getDashboardItemByType: (props: {type: VisualizationType; isHalfScreen: boolean}) => JSX.Element;
30
32
  actionButtons: {
31
33
  icicle: JSX.Element;
32
34
  table: JSX.Element;
@@ -0,0 +1,61 @@
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 {FC, PropsWithChildren, createContext, useContext} from 'react';
15
+
16
+ import {useURLState} from '@parca/components';
17
+
18
+ import {VisualizationType} from '../types/visualization';
19
+
20
+ interface DashboardContextType {
21
+ dashboardItems: string[];
22
+ setDashboardItems: (items: string[]) => void;
23
+ handleClosePanel: (visualizationType: VisualizationType) => void;
24
+ isMultiPanelView: boolean;
25
+ }
26
+
27
+ const DashboardContext = createContext<DashboardContextType | undefined>(undefined);
28
+
29
+ export const DashboardProvider: FC<PropsWithChildren> = ({children}) => {
30
+ const [dashboardItems, setDashboardItems] = useURLState<string[]>('dashboard_items', {
31
+ alwaysReturnArray: true,
32
+ });
33
+
34
+ const handleClosePanel = (visualizationType: VisualizationType): void => {
35
+ const newDashboardItems = dashboardItems.filter(item => item !== visualizationType);
36
+ setDashboardItems(newDashboardItems);
37
+ };
38
+
39
+ const isMultiPanelView = dashboardItems.length > 1;
40
+
41
+ return (
42
+ <DashboardContext.Provider
43
+ value={{
44
+ dashboardItems,
45
+ setDashboardItems,
46
+ handleClosePanel,
47
+ isMultiPanelView,
48
+ }}
49
+ >
50
+ {children}
51
+ </DashboardContext.Provider>
52
+ );
53
+ };
54
+
55
+ export const useDashboard = (): DashboardContextType => {
56
+ const context = useContext(DashboardContext);
57
+ if (context === undefined) {
58
+ throw new Error('useDashboard must be used within a DashboardProvider');
59
+ }
60
+ return context;
61
+ };
@@ -13,7 +13,7 @@
13
13
 
14
14
  import {ReactNode, createContext, useContext} from 'react';
15
15
 
16
- import {ProfileSource} from '../ProfileSource';
16
+ import {ProfileSource} from '../../ProfileSource';
17
17
 
18
18
  interface Props {
19
19
  profileSource?: ProfileSource;
@@ -0,0 +1,69 @@
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 {useEffect, useState} from 'react';
15
+
16
+ import graphviz from 'graphviz-wasm';
17
+
18
+ import {Callgraph as CallgraphType} from '@parca/client';
19
+
20
+ import {jsonToDot} from '../../Callgraph/utils';
21
+
22
+ interface UseGraphvizProps {
23
+ callgraphData?: CallgraphType;
24
+ width?: number;
25
+ colorRange: [string, string];
26
+ }
27
+
28
+ export const useGraphviz = ({
29
+ callgraphData,
30
+ width,
31
+ colorRange,
32
+ }: UseGraphvizProps): {
33
+ graphvizLoaded: boolean;
34
+ callgraphSVG: string | undefined;
35
+ } => {
36
+ const [graphvizLoaded, setGraphvizLoaded] = useState(false);
37
+ const [callgraphSVG, setCallgraphSVG] = useState<string | undefined>(undefined);
38
+
39
+ useEffect(() => {
40
+ async function loadGraphviz(): Promise<void> {
41
+ await graphviz.loadWASM();
42
+ setGraphvizLoaded(true);
43
+ }
44
+ void loadGraphviz();
45
+ }, []);
46
+
47
+ useEffect(() => {
48
+ async function loadCallgraphSVG(
49
+ graph: CallgraphType,
50
+ width: number,
51
+ colorRange: [string, string]
52
+ ): Promise<void> {
53
+ await setCallgraphSVG(undefined);
54
+ const dataAsDot = await jsonToDot({
55
+ graph,
56
+ width,
57
+ colorRange,
58
+ });
59
+ const svgGraph = await graphviz.layout(dataAsDot, 'svg', 'dot');
60
+ await setCallgraphSVG(svgGraph);
61
+ }
62
+
63
+ if (graphvizLoaded && callgraphData != null && width != null) {
64
+ void loadCallgraphSVG(callgraphData, width, colorRange);
65
+ }
66
+ }, [graphvizLoaded, callgraphData, width, colorRange]);
67
+
68
+ return {graphvizLoaded, callgraphSVG};
69
+ };
@@ -0,0 +1,59 @@
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 {useMemo} from 'react';
15
+
16
+ import {Table as ArrowTable, tableFromIPC} from 'apache-arrow';
17
+
18
+ import {FlamegraphArrow} from '@parca/client';
19
+
20
+ import useMappingList, {
21
+ useFilenamesList,
22
+ } from '../../ProfileIcicleGraph/IcicleGraphArrow/useMappingList';
23
+
24
+ interface UseProfileMetadataProps {
25
+ flamegraphArrow?: FlamegraphArrow;
26
+ metadataMappingFiles?: string[];
27
+ metadataLoading: boolean;
28
+ colorBy: string;
29
+ }
30
+
31
+ export const useProfileMetadata = ({
32
+ flamegraphArrow,
33
+ metadataMappingFiles,
34
+ metadataLoading,
35
+ colorBy,
36
+ }: UseProfileMetadataProps): {
37
+ table: ArrowTable<any> | null;
38
+ mappingsList: string[];
39
+ filenamesList: string[];
40
+ colorMappings: string[];
41
+ metadataLoading: boolean;
42
+ } => {
43
+ const table: ArrowTable<any> | null = useMemo(() => {
44
+ return flamegraphArrow !== undefined ? tableFromIPC(flamegraphArrow.record) : null;
45
+ }, [flamegraphArrow]);
46
+
47
+ const mappingsList = useMappingList(metadataMappingFiles);
48
+ const filenamesList = useFilenamesList(table);
49
+
50
+ const colorMappings = colorBy === 'binary' ? mappingsList : filenamesList;
51
+
52
+ return {
53
+ table,
54
+ mappingsList,
55
+ filenamesList,
56
+ colorMappings,
57
+ metadataLoading,
58
+ };
59
+ };