@parca/profile 0.16.426 → 0.16.427
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/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.js +1 -1
- package/dist/ProfileIcicleGraph/index.d.ts +1 -1
- package/dist/ProfileIcicleGraph/index.d.ts.map +1 -1
- package/dist/ProfileIcicleGraph/index.js +4 -59
- package/dist/ProfileView/VisualizationPanel.d.ts.map +1 -1
- package/dist/ProfileView/VisualizationPanel.js +2 -3
- package/dist/ProfileView/index.d.ts.map +1 -1
- package/dist/ProfileView/index.js +21 -14
- package/dist/Table/ColumnsVisibility.js +1 -1
- package/dist/Table/index.d.ts +6 -0
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +45 -21
- package/dist/components/ActionButtons/GroupByDropdown.d.ts.map +1 -0
- package/dist/{ProfileIcicleGraph → components}/ActionButtons/GroupByDropdown.js +1 -1
- package/dist/components/FilterByFunctionButton.d.ts.map +1 -0
- package/dist/components/ShareButton/ResultBox.d.ts.map +1 -0
- package/dist/components/ShareButton/index.d.ts +14 -0
- package/dist/components/ShareButton/index.d.ts.map +1 -0
- package/dist/components/{ProfileShareButton → ShareButton}/index.js +28 -5
- package/dist/components/ViewSelector/Dropdown.d.ts +30 -0
- package/dist/components/ViewSelector/Dropdown.d.ts.map +1 -0
- package/dist/components/ViewSelector/Dropdown.js +41 -0
- package/dist/components/ViewSelector/index.d.ts +3 -0
- package/dist/components/ViewSelector/index.d.ts.map +1 -0
- package/dist/{ProfileView/ViewSelector.js → components/ViewSelector/index.js} +25 -12
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts +9 -0
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.d.ts.map +1 -0
- package/dist/components/VisualisationToolbar/MultiLevelDropdown.js +123 -0
- package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts +9 -0
- package/dist/components/VisualisationToolbar/TableColumnsDropdown.d.ts.map +1 -0
- package/dist/components/VisualisationToolbar/TableColumnsDropdown.js +189 -0
- package/dist/components/VisualisationToolbar/index.d.ts +25 -0
- package/dist/components/VisualisationToolbar/index.d.ts.map +1 -0
- package/dist/components/VisualisationToolbar/index.js +55 -0
- package/dist/styles.css +1 -1
- package/package.json +4 -4
- package/src/ProfileIcicleGraph/IcicleGraphArrow/ContextMenu.tsx +1 -1
- package/src/ProfileIcicleGraph/index.tsx +3 -206
- package/src/ProfileView/VisualizationPanel.tsx +1 -6
- package/src/ProfileView/index.tsx +46 -56
- package/src/Table/ColumnsVisibility.tsx +1 -1
- package/src/Table/index.tsx +64 -42
- package/src/{ProfileIcicleGraph → components}/ActionButtons/GroupByDropdown.tsx +1 -1
- package/src/components/{ProfileShareButton → ShareButton}/index.tsx +88 -24
- package/src/components/ViewSelector/Dropdown.tsx +181 -0
- package/src/{ProfileView/ViewSelector.tsx → components/ViewSelector/index.tsx} +32 -39
- package/src/components/VisualisationToolbar/MultiLevelDropdown.tsx +258 -0
- package/src/components/VisualisationToolbar/TableColumnsDropdown.tsx +222 -0
- package/src/components/VisualisationToolbar/index.tsx +171 -0
- package/dist/ProfileIcicleGraph/ActionButtons/GroupByDropdown.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/ActionButtons/SortBySelect.d.ts +0 -7
- package/dist/ProfileIcicleGraph/ActionButtons/SortBySelect.d.ts.map +0 -1
- package/dist/ProfileIcicleGraph/ActionButtons/SortBySelect.js +0 -44
- package/dist/ProfileView/FilterByFunctionButton.d.ts.map +0 -1
- package/dist/ProfileView/ViewSelector.d.ts +0 -13
- package/dist/ProfileView/ViewSelector.d.ts.map +0 -1
- package/dist/components/ProfileShareButton/ResultBox.d.ts.map +0 -1
- package/dist/components/ProfileShareButton/index.d.ts +0 -9
- package/dist/components/ProfileShareButton/index.d.ts.map +0 -1
- package/src/ProfileIcicleGraph/ActionButtons/SortBySelect.tsx +0 -81
- /package/dist/{ProfileIcicleGraph → components}/ActionButtons/GroupByDropdown.d.ts +0 -0
- /package/dist/{ProfileView → components}/FilterByFunctionButton.d.ts +0 -0
- /package/dist/{ProfileView → components}/FilterByFunctionButton.js +0 -0
- /package/dist/components/{ProfileShareButton → ShareButton}/ResultBox.d.ts +0 -0
- /package/dist/components/{ProfileShareButton → ShareButton}/ResultBox.js +0 -0
- /package/src/{ProfileView → components}/FilterByFunctionButton.tsx +0 -0
- /package/src/components/{ProfileShareButton → ShareButton}/ResultBox.tsx +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,10 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [0.16.427](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.426...@parca/profile@0.16.427) (2024-08-19)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
6
10
|
## [0.16.426](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.425...@parca/profile@0.16.426) (2024-08-19)
|
|
7
11
|
|
|
8
12
|
**Note:** Version bump only for package @parca/profile
|
|
@@ -78,6 +78,6 @@ const ContextMenu = ({ menuId, table, total, totalUnfiltered, row, level, compar
|
|
|
78
78
|
{ id: 'Build Id', value: buildIdText },
|
|
79
79
|
];
|
|
80
80
|
const nonEmptyValuesToCopy = valuesToCopy.filter(({ value }) => value !== '');
|
|
81
|
-
return (_jsxs(Menu, { id: menuId, onVisibilityChange: trackVisibility, theme: isDarkMode ? 'dark' : '', children: [_jsxs(Item, { id: "view-source-file", onClick: handleViewSourceFile, disabled: enableSourcesView === false || !isSourceAvailable, children: [_jsx("div", { "data-tooltip-id": "view-source-file-help", "data-tooltip-content": "There is no source code uploaded for this build", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "wpf:view-file" }), _jsx("div", { children: "View source file" })] }) }), !isSourceAvailable ? _jsx(Tooltip, { id: "view-source-file-help" }) : null] }), _jsx(Item, { id: "reset-view", onClick: handleResetView, disabled: curPath.length === 0, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "system-uicons:reset" }), _jsx("div", { children: "Reset
|
|
81
|
+
return (_jsxs(Menu, { id: menuId, onVisibilityChange: trackVisibility, theme: isDarkMode ? 'dark' : '', children: [_jsxs(Item, { id: "view-source-file", onClick: handleViewSourceFile, disabled: enableSourcesView === false || !isSourceAvailable, children: [_jsx("div", { "data-tooltip-id": "view-source-file-help", "data-tooltip-content": "There is no source code uploaded for this build", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "wpf:view-file" }), _jsx("div", { children: "View source file" })] }) }), !isSourceAvailable ? _jsx(Tooltip, { id: "view-source-file-help" }) : null] }), _jsx(Item, { id: "reset-view", onClick: handleResetView, disabled: curPath.length === 0, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "system-uicons:reset" }), _jsx("div", { children: "Reset graph" })] }) }), _jsxs(Item, { id: "hide-binary", onClick: () => hideBinary(getLastItem(mappingFile)), disabled: mappingFile === null || mappingFile === '', children: [_jsx("div", { "data-tooltip-id": "hide-binary-help", "data-tooltip-content": "Hide all frames for this binary", children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "bx:bxs-hide" }), _jsxs("div", { children: ["Hide Binary ", mappingFile !== null && `(${getLastItem(mappingFile)})`] })] }) }), _jsx(Tooltip, { place: "left", id: "hide-binary-help" })] }), _jsx(Submenu, { label: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "ph:copy" }), _jsx("div", { children: "Copy" })] }), children: _jsx("div", { className: "max-h-[300px] overflow-scroll", children: nonEmptyValuesToCopy.map(({ id, value }) => (_jsx(Item, { id: id, onClick: () => handleCopyItem(value), className: "dark:bg-gray-800", children: _jsxs("div", { className: "flex flex-col dark:text-gray-300 hover:dark:text-gray-100", children: [_jsx("div", { className: "text-sm", children: id }), _jsx("div", { className: "text-xs", children: truncateString(value, 30) })] }) }, id))) }) }), _jsx(Separator, {}), _jsx(Item, { id: "dock-tooltip", onClick: handleDockTooltip, children: _jsxs("div", { className: "flex w-full items-center gap-2", children: [_jsx(Icon, { icon: "bx:dock-bottom" }), isGraphTooltipDocked ? 'Undock tooltip' : 'Dock tooltip'] }) })] }));
|
|
82
82
|
};
|
|
83
83
|
export default ContextMenu;
|
|
@@ -18,6 +18,6 @@ interface ProfileIcicleGraphProps {
|
|
|
18
18
|
mappings?: string[];
|
|
19
19
|
mappingsLoading?: boolean;
|
|
20
20
|
}
|
|
21
|
-
declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading,
|
|
21
|
+
declare const ProfileIcicleGraph: ({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, error, width, isHalfScreen, mappings, }: ProfileIcicleGraphProps) => JSX.Element;
|
|
22
22
|
export default ProfileIcicleGraph;
|
|
23
23
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileIcicleGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileIcicleGraph/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAI1D,OAAO,EAAC,UAAU,EAAE,eAAe,EAAC,MAAM,eAAe,CAAC;AAE1D,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAY1C,MAAM,MAAM,aAAa,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;AAEpE,UAAU,uBAAuB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;IACvB,aAAa,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,YAAY,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAMD,QAAA,MAAM,kBAAkB,2HAarB,uBAAuB,KAAG,GAAG,CAAC,OAqKhC,CAAC;AAEF,eAAe,kBAAkB,CAAC"}
|
|
@@ -11,16 +11,12 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
11
11
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
12
|
// See the License for the specific language governing permissions and
|
|
13
13
|
// limitations under the License.
|
|
14
|
-
import {
|
|
15
|
-
import { Icon } from '@iconify/react';
|
|
14
|
+
import { useEffect, useMemo, useState } from 'react';
|
|
16
15
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
17
|
-
import {
|
|
18
|
-
import { USER_PREFERENCES, useUserPreference } from '@parca/hooks';
|
|
16
|
+
import { IcicleGraphSkeleton, useParcaContext, useURLState } from '@parca/components';
|
|
19
17
|
import { capitalizeOnlyFirstLetter, divide, selectQueryParam } from '@parca/utilities';
|
|
20
18
|
import { useProfileViewContext } from '../ProfileView/ProfileViewContext';
|
|
21
19
|
import DiffLegend from '../components/DiffLegend';
|
|
22
|
-
import GroupByDropdown from './ActionButtons/GroupByDropdown';
|
|
23
|
-
import SortBySelect from './ActionButtons/SortBySelect';
|
|
24
20
|
import { IcicleGraph } from './IcicleGraph';
|
|
25
21
|
import { FIELD_FUNCTION_NAME, IcicleGraphArrow } from './IcicleGraphArrow';
|
|
26
22
|
import ColorStackLegend from './IcicleGraphArrow/ColorStackLegend';
|
|
@@ -29,52 +25,17 @@ const numberFormatter = new Intl.NumberFormat('en-US');
|
|
|
29
25
|
const ErrorContent = ({ errorMessage }) => {
|
|
30
26
|
return _jsx("div", { className: "flex justify-center p-10", children: errorMessage });
|
|
31
27
|
};
|
|
32
|
-
const
|
|
33
|
-
const [colorStackLegend, setStoreColorStackLegend] = useURLState('color_stack_legend');
|
|
34
|
-
const [binaryFrameFilter, setBinaryFrameFilter] = useURLState('binary_frame_filter');
|
|
35
|
-
const { compareMode } = useProfileViewContext();
|
|
36
|
-
const isColorStackLegendEnabled = colorStackLegend === 'true';
|
|
37
|
-
const [colorProfileName] = useUserPreference(USER_PREFERENCES.FLAMEGRAPH_COLOR_PROFILE.key);
|
|
38
|
-
const setColorStackLegend = useCallback((value) => {
|
|
39
|
-
setStoreColorStackLegend(value);
|
|
40
|
-
}, [setStoreColorStackLegend]);
|
|
41
|
-
const resetLegend = () => {
|
|
42
|
-
setBinaryFrameFilter([]);
|
|
43
|
-
};
|
|
44
|
-
return (_jsx(_Fragment, { children: colorProfileName === 'default' || compareMode ? null : (_jsx(_Fragment, { children: isHalfScreen ? (_jsxs(_Fragment, { children: [_jsx(IconButton, { className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]", icon: isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye', toolTipText: isColorStackLegendEnabled ? 'Hide legend' : 'Show legend', onClick: () => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true'), id: "h-show-legend-button" }), binaryFrameFilter !== undefined && binaryFrameFilter.length > 0 && (_jsx(IconButton, { className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center !py-2 !px-3 cursor-pointer min-h-[38px]", icon: "system-uicons:reset", toolTipText: "Reset the legend selection", onClick: () => resetLegend(), id: "h-reset-legend-button" }))] })) : (_jsxs(_Fragment, { children: [_jsxs(Button, { className: "gap-2 w-max", variant: "neutral", onClick: () => setColorStackLegend(isColorStackLegendEnabled ? 'false' : 'true'), id: "h-show-legend-button", children: [isColorStackLegendEnabled ? 'Hide legend' : 'Show legend', _jsx(Icon, { icon: isColorStackLegendEnabled ? 'ph:eye-closed' : 'ph:eye', width: 20 })] }), binaryFrameFilter !== undefined && binaryFrameFilter.length > 0 && (_jsxs(Button, { className: "gap-2 w-max", variant: "neutral", onClick: () => resetLegend(), id: "h-reset-legend-button", children: ["Reset Legend", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }))] })) })) }));
|
|
45
|
-
};
|
|
46
|
-
const GroupAndSortActionButtons = () => {
|
|
47
|
-
const [storeSortBy, setStoreSortBy] = useURLState('sort_by', {
|
|
48
|
-
defaultValue: FIELD_FUNCTION_NAME,
|
|
49
|
-
});
|
|
50
|
-
const { compareMode } = useProfileViewContext();
|
|
51
|
-
const [groupBy, setStoreGroupBy] = useURLState('group_by', {
|
|
52
|
-
defaultValue: [FIELD_FUNCTION_NAME],
|
|
53
|
-
alwaysReturnArray: true,
|
|
54
|
-
});
|
|
55
|
-
const setGroupBy = useCallback((keys) => {
|
|
56
|
-
setStoreGroupBy(keys);
|
|
57
|
-
}, [setStoreGroupBy]);
|
|
58
|
-
const toggleGroupBy = useCallback((key) => {
|
|
59
|
-
groupBy.includes(key)
|
|
60
|
-
? setGroupBy(groupBy.filter(v => v !== key)) // remove
|
|
61
|
-
: setGroupBy([...groupBy, key]); // add
|
|
62
|
-
}, [groupBy, setGroupBy]);
|
|
63
|
-
return (_jsxs(_Fragment, { children: [_jsx(GroupByDropdown, { groupBy: groupBy, toggleGroupBy: toggleGroupBy }), _jsx(SortBySelect, { compareMode: compareMode, sortBy: storeSortBy, setSortBy: setStoreSortBy })] }));
|
|
64
|
-
};
|
|
65
|
-
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, setActionButtons, error, width, isHalfScreen, mappings, }) {
|
|
28
|
+
const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, total, filtered, curPath, setNewCurPath, profileType, loading, error, width, isHalfScreen, mappings, }) {
|
|
66
29
|
const { onError, authenticationErrorMessage, isDarkMode } = useParcaContext();
|
|
67
30
|
const { compareMode } = useProfileViewContext();
|
|
68
31
|
const [isLoading, setIsLoading] = useState(true);
|
|
69
32
|
const isColorStackLegendEnabled = selectQueryParam('color_stack_legend') === 'true';
|
|
70
33
|
const mappingsList = useMappingList(mappings);
|
|
71
34
|
const [storeSortBy = FIELD_FUNCTION_NAME] = useURLState('sort_by');
|
|
72
|
-
const [invertStack = '', setInvertStack] = useURLState('invert_call_stack');
|
|
73
|
-
const isInvert = invertStack === 'true';
|
|
74
35
|
// By default, we want delta profiles (CPU) to be relatively compared.
|
|
75
36
|
// For non-delta profiles, like goroutines or memory, we want the profiles to be compared absolutely.
|
|
76
37
|
const compareAbsoluteDefault = profileType?.delta === false ? 'true' : 'false';
|
|
77
|
-
const [compareAbsolute = compareAbsoluteDefault
|
|
38
|
+
const [compareAbsolute = compareAbsoluteDefault] = useURLState('compare_absolute');
|
|
78
39
|
const isCompareAbsolute = compareAbsolute === 'true';
|
|
79
40
|
const [totalFormatted, totalUnfilteredFormatted, isTrimmed, trimmedFormatted, trimmedPercentage, isFiltered, filteredPercentage,] = useMemo(() => {
|
|
80
41
|
if (graph === undefined && arrow === undefined) {
|
|
@@ -94,22 +55,6 @@ const ProfileIcicleGraph = function ProfileIcicleGraphNonMemo({ graph, arrow, to
|
|
|
94
55
|
numberFormatter.format(divide(total * 100n, totalUnfilteredDivisor)),
|
|
95
56
|
];
|
|
96
57
|
}, [graph, arrow, filtered, total]);
|
|
97
|
-
useEffect(() => {
|
|
98
|
-
setActionButtons?.(_jsx("div", { className: "flex w-full justify-end gap-2 pb-2", children: _jsxs("div", { className: "ml-2 flex w-full flex-col items-start justify-between gap-2 md:flex-row md:items-end", children: [_jsx(GroupAndSortActionButtons, {}), isHalfScreen ? (_jsx(IconButton, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', toolTipText: isInvert ? 'Original Call Stack' : 'Invert Call Stack', onClick: () => setInvertStack(isInvert ? '' : 'true'), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setInvertStack(isInvert ? '' : 'true'), children: [isInvert ? 'Original Call Stack' : 'Invert Call Stack', _jsx(Icon, { icon: isInvert ? 'ph:sort-ascending' : 'ph:sort-descending', width: 20 })] })), _jsx(ShowHideLegendButton, { isHalfScreen: isHalfScreen }), compareMode && (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setCompareAbsolute(isCompareAbsolute ? '' : 'true'), children: [isCompareAbsolute ? 'Compare Relative' : 'Compare Absolute', _jsx(Icon, { icon: isCompareAbsolute ? 'fluent-mdl2:compare' : 'fluent-mdl2:compare-uneven', width: 20 })] })), isHalfScreen ? (_jsx(IconButton, { icon: "system-uicons:reset", disabled: curPath.length === 0, toolTipText: "Reset View", onClick: () => setNewCurPath([]), className: "rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 items-center flex border border-gray-200 dark:border-gray-600 dark:text-white justify-center py-2 px-3 cursor-pointer min-h-[38px]" })) : (_jsxs(Button, { variant: "neutral", className: "gap-2 w-max", onClick: () => setNewCurPath([]), disabled: curPath.length === 0, children: ["Reset View", _jsx(Icon, { icon: "system-uicons:reset", width: 20 })] }))] }) }));
|
|
99
|
-
}, [
|
|
100
|
-
isInvert,
|
|
101
|
-
setInvertStack,
|
|
102
|
-
arrow,
|
|
103
|
-
curPath,
|
|
104
|
-
setNewCurPath,
|
|
105
|
-
setActionButtons,
|
|
106
|
-
loading,
|
|
107
|
-
isHalfScreen,
|
|
108
|
-
isLoading,
|
|
109
|
-
compareMode,
|
|
110
|
-
isCompareAbsolute,
|
|
111
|
-
setCompareAbsolute,
|
|
112
|
-
]);
|
|
113
58
|
const loadingState = !loading && (arrow !== undefined || graph !== undefined) && mappings !== undefined;
|
|
114
59
|
useEffect(() => {
|
|
115
60
|
if (loadingState) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"VisualizationPanel.d.ts","sourceRoot":"","sources":["../../src/ProfileView/VisualizationPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,KAAK,EAAC,gCAAgC,EAAC,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"VisualizationPanel.d.ts","sourceRoot":"","sources":["../../src/ProfileView/VisualizationPanel.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,KAAK,EAAC,gCAAgC,EAAC,MAAM,qBAAqB,CAAC;AAK1E,UAAU,KAAK;IACb,aAAa,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,gBAAgB,EAAE,OAAO,CAAC;IAC1B,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK,IAAI,CAAC;IAClD,eAAe,EAAE,gCAAgC,GAAG,IAAI,GAAG,SAAS,CAAC;IACrE,sBAAsB,EAAE,CAAC,KAAK,EAAE;QAC9B,IAAI,EAAE,MAAM,CAAC;QACb,YAAY,EAAE,OAAO,CAAC;QACtB,gBAAgB,EAAE,CAAC,aAAa,EAAE,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;KACxD,KAAK,GAAG,CAAC,OAAO,CAAC;CACnB;AAED,eAAO,MAAM,kBAAkB,mCAsD7B,CAAC"}
|
|
@@ -16,11 +16,10 @@ import { Icon } from '@iconify/react';
|
|
|
16
16
|
import cx from 'classnames';
|
|
17
17
|
import { IconButton, useParcaContext } from '@parca/components';
|
|
18
18
|
import { CloseIcon } from '@parca/icons';
|
|
19
|
-
|
|
20
|
-
export const VisualizationPanel = React.memo(function VisualizationPanel({ dashboardItem, index, isMultiPanelView, handleClosePanel, dragHandleProps, getDashboardItemByType, }) {
|
|
19
|
+
export const VisualizationPanel = React.memo(function VisualizationPanel({ dashboardItem, isMultiPanelView, handleClosePanel, dragHandleProps, getDashboardItemByType, }) {
|
|
21
20
|
const [actionButtons, setActionButtons] = useState(_jsx(_Fragment, {}));
|
|
22
21
|
const { flamegraphHint } = useParcaContext();
|
|
23
|
-
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full items-center justify-end gap-2 pb-2
|
|
22
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex w-full items-center justify-end gap-2 pb-2", children: [_jsxs("div", { className: cx('flex w-full justify-between flex-col-reverse md:flex-row', isMultiPanelView && dashboardItem === 'icicle' ? 'items-end gap-x-2' : 'items-end'), children: [_jsxs("div", { className: "flex items-center", children: [_jsx("div", { className: cx(isMultiPanelView ? '' : 'hidden', 'flex items-center'), ...dragHandleProps, children: _jsx(Icon, { className: "text-xl", icon: "material-symbols:drag-indicator" }) }), _jsx("div", { className: "flex gap-2", children: actionButtons })] }), _jsx("div", { className: cx('flex flex-row items-center gap-4', isMultiPanelView && dashboardItem === 'icicle' && 'pb-[10px]'), children: dashboardItem === 'icicle' && flamegraphHint != null ? (_jsx("div", { className: "px-2", children: flamegraphHint })) : null })] }), isMultiPanelView && (_jsx(IconButton, { className: "py-0", onClick: () => handleClosePanel(dashboardItem), icon: _jsx(CloseIcon, {}) }))] }), getDashboardItemByType({
|
|
24
23
|
type: dashboardItem,
|
|
25
24
|
isHalfScreen: isMultiPanelView,
|
|
26
25
|
setActionButtons,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ProfileView/index.tsx"],"names":[],"mappings":"AA0BA,OAAO,EACL,SAAS,IAAI,aAAa,EAC1B,UAAU,EACV,eAAe,EACf,kBAAkB,EAClB,MAAM,EACN,UAAU,EACV,GAAG,EACJ,MAAM,eAAe,CAAC;AAUvB,OAAO,EAAC,aAAa,EAAC,MAAM,kBAAkB,CAAC;AAO/C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,CAAC,EAAE,eAAe,CAAC;IACxB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,UAAU,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,UAAU,aAAa;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,aAAa,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,UAAU,UAAU;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC;CACb;AAED,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,UAAU,CAAC,EAAE,UAAU,CAAC;IACxB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAWD,eAAO,MAAM,WAAW,0JAYrB,gBAAgB,KAAG,GAAG,CAAC,OAmUzB,CAAC"}
|
|
@@ -12,25 +12,23 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
12
12
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
13
|
// See the License for the specific language governing permissions and
|
|
14
14
|
// limitations under the License.
|
|
15
|
-
import { Profiler, useEffect, useState } from 'react';
|
|
16
|
-
import { Icon } from '@iconify/react';
|
|
15
|
+
import { Profiler, useCallback, useEffect, useState } from 'react';
|
|
17
16
|
import cx from 'classnames';
|
|
18
17
|
import { scaleLinear } from 'd3';
|
|
19
18
|
import graphviz from 'graphviz-wasm';
|
|
20
19
|
import { DragDropContext, Draggable, Droppable, } from 'react-beautiful-dnd';
|
|
21
|
-
import {
|
|
20
|
+
import { ConditionalWrapper, KeyDownProvider, useParcaContext, useURLState } from '@parca/components';
|
|
22
21
|
import { useContainerDimensions } from '@parca/hooks';
|
|
23
22
|
import { selectDarkMode, useAppSelector } from '@parca/store';
|
|
24
23
|
import { getNewSpanColor, selectQueryParam } from '@parca/utilities';
|
|
25
24
|
import { Callgraph } from '../';
|
|
26
25
|
import { jsonToDot } from '../Callgraph/utils';
|
|
27
26
|
import ProfileIcicleGraph from '../ProfileIcicleGraph';
|
|
27
|
+
import { FIELD_FUNCTION_NAME } from '../ProfileIcicleGraph/IcicleGraphArrow';
|
|
28
28
|
import { SourceView } from '../SourceView';
|
|
29
29
|
import { Table } from '../Table';
|
|
30
|
-
import
|
|
31
|
-
import FilterByFunctionButton from './FilterByFunctionButton';
|
|
30
|
+
import VisualisationToolbar from '../components/VisualisationToolbar';
|
|
32
31
|
import { ProfileViewContextProvider } from './ProfileViewContext';
|
|
33
|
-
import ViewSelector from './ViewSelector';
|
|
34
32
|
import { VisualizationPanel } from './VisualizationPanel';
|
|
35
33
|
function arrayEquals(a, b) {
|
|
36
34
|
return (Array.isArray(a) &&
|
|
@@ -50,7 +48,7 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
|
|
|
50
48
|
const [currentSearchString, setSearchString] = useURLState('search_string');
|
|
51
49
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
52
50
|
const isMultiPanelView = dashboardItems.length > 1;
|
|
53
|
-
const { perf, profileViewExternalMainActions
|
|
51
|
+
const { perf, profileViewExternalMainActions } = useParcaContext();
|
|
54
52
|
useEffect(() => {
|
|
55
53
|
// Reset the current path when the profile source changes
|
|
56
54
|
setCurPath([]);
|
|
@@ -143,17 +141,26 @@ export const ProfileView = ({ total, filtered, flamegraphData, topTableData, cal
|
|
|
143
141
|
const headerParts = profileSourceString?.split('"') ?? [];
|
|
144
142
|
const compareMode = compare === true ||
|
|
145
143
|
(selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true');
|
|
146
|
-
|
|
144
|
+
const [groupBy, setStoreGroupBy] = useURLState('group_by', {
|
|
145
|
+
defaultValue: [FIELD_FUNCTION_NAME],
|
|
146
|
+
alwaysReturnArray: true,
|
|
147
|
+
});
|
|
148
|
+
const setGroupBy = useCallback((keys) => {
|
|
149
|
+
setStoreGroupBy(keys);
|
|
150
|
+
}, [setStoreGroupBy]);
|
|
151
|
+
const toggleGroupBy = useCallback((key) => {
|
|
152
|
+
groupBy.includes(key)
|
|
153
|
+
? setGroupBy(groupBy.filter(v => v !== key)) // remove
|
|
154
|
+
: setGroupBy([...groupBy, key]); // add
|
|
155
|
+
}, [groupBy, setGroupBy]);
|
|
156
|
+
return (_jsx(KeyDownProvider, { children: _jsxs(ProfileViewContextProvider, { value: { profileSource, compareMode }, children: [_jsx("div", { className: cx('mb-4 flex w-full', hasProfileSource || profileViewExternalMainActions != null
|
|
147
157
|
? 'justify-between'
|
|
148
158
|
: 'justify-end', {
|
|
149
159
|
'items-end': !hasProfileSource && profileViewExternalMainActions != null,
|
|
150
160
|
'items-center': hasProfileSource,
|
|
151
|
-
}), children:
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
e.preventDefault();
|
|
155
|
-
onDownloadPProf();
|
|
156
|
-
}, disabled: pprofDownloading, id: "h-download-pprof", children: [pprofDownloading != null && pprofDownloading ? 'Downloading...' : 'Download pprof', _jsx(Icon, { icon: "material-symbols:download", width: 20 })] }), _jsx(ViewSelector, { defaultValue: "", position: -1, placeholderText: "Add panel", icon: _jsx(Icon, { icon: "material-symbols:add", width: 20 }), addView: true, disabled: isMultiPanelView || dashboardItems.length < 1, id: "h-add-panel" })] })] }), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DragDropContext, { onDragEnd: onDragEnd, children: _jsx(Droppable, { droppableId: "droppable", direction: "horizontal", children: provided => (_jsx("div", { ref: provided.innerRef, className: cx('grid w-full gap-2', isMultiPanelView ? 'grid-cols-2' : 'grid-cols-1'), ...provided.droppableProps, children: dashboardItems.map((dashboardItem, index) => {
|
|
161
|
+
}), children: _jsxs("div", { children: [hasProfileSource && (_jsxs("div", { className: "flex items-center gap-1", children: [_jsx("div", { className: "text-sm font-medium capitalize", children: headerParts.length > 0 ? headerParts[0].replace(/"/g, '') : '' }), _jsx("div", { className: "text-xs", children: headerParts.length > 1
|
|
162
|
+
? headerParts[headerParts.length - 1].replace(/"/g, '')
|
|
163
|
+
: '' })] })), profileViewExternalMainActions != null ? profileViewExternalMainActions : null] }) }), _jsx(VisualisationToolbar, { groupBy: groupBy, toggleGroupBy: toggleGroupBy, hasProfileSource: hasProfileSource, pprofdownloading: pprofDownloading, profileSource: profileSource, queryClient: queryClient, onDownloadPProf: onDownloadPProf, isMultiPanelView: isMultiPanelView, dashboardItems: dashboardItems, curPath: curPath, setNewCurPath: setNewCurPath, profileType: profileSource?.ProfileType(), total: total, filtered: filtered, currentSearchString: currentSearchString, setSearchString: setSearchString }), _jsx("div", { className: "w-full", ref: ref, children: _jsx(DragDropContext, { onDragEnd: onDragEnd, children: _jsx(Droppable, { droppableId: "droppable", direction: "horizontal", children: provided => (_jsx("div", { ref: provided.innerRef, className: cx('grid w-full gap-2', isMultiPanelView ? 'grid-cols-2' : 'grid-cols-1'), ...provided.droppableProps, children: dashboardItems.map((dashboardItem, index) => {
|
|
157
164
|
return (_jsx(Draggable, { draggableId: dashboardItem, index: index, isDragDisabled: !isMultiPanelView, children: (provided, snapshot) => (_createElement("div", { ref: provided.innerRef, ...provided.draggableProps, key: dashboardItem, className: cx('w-full rounded p-2 shadow dark:border dark:border-gray-700 dark:bg-gray-700 min-h-96', snapshot.isDragging
|
|
158
165
|
? 'bg-gray-200 dark:bg-gray-500'
|
|
159
166
|
: 'bg-white dark:bg-gray-700') },
|
|
@@ -15,7 +15,7 @@ import { Fragment } from 'react';
|
|
|
15
15
|
import { Menu, Transition } from '@headlessui/react';
|
|
16
16
|
import { Icon } from '@iconify/react';
|
|
17
17
|
const ColumnsVisibility = ({ columns, visibility, setVisibility, }) => {
|
|
18
|
-
return (_jsx("div", { children: _jsxs(Menu, { as: "div", className: "relative text-left", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-10 text-left text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 sm:text-sm", children: [_jsx("span", { className: "block overflow-x-hidden text-ellipsis", children: "
|
|
18
|
+
return (_jsx("div", { children: _jsxs(Menu, { as: "div", className: "relative text-left", children: [_jsx("div", { children: _jsxs(Menu.Button, { className: "relative w-full cursor-default rounded-md border bg-white py-2 pl-3 pr-10 text-left text-sm shadow-sm focus:border-indigo-500 focus:outline-none focus:ring-1 focus:ring-indigo-500 dark:border-gray-600 dark:bg-gray-900 sm:text-sm", children: [_jsx("span", { className: "block overflow-x-hidden text-ellipsis", children: "Multiple" }), _jsx("span", { className: "pointer-events-none absolute inset-y-0 right-0 ml-3 flex items-center pr-2 text-gray-400", children: _jsx(Icon, { icon: "heroicons:chevron-down-20-solid", "aria-hidden": "true" }) })] }) }), _jsx(Transition, { as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx(Menu.Items, { className: "absolute left-0 z-10 mt-1 min-w-[400px] overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm", children: _jsx("div", { className: "p-4", children: _jsx("fieldset", { children: _jsx("div", { className: "space-y-5", children: columns.map(col => (_jsxs("div", { className: "relative flex items-start", children: [_jsx("div", { className: "flex h-6 items-center", children: _jsx("input", { id: col.id, name: col.id, type: "checkbox", className: "h-4 w-4 rounded border-gray-300 text-indigo-600 focus:ring-indigo-600", checked: visibility[col.id ?? ''] ?? false, onChange: () => {
|
|
19
19
|
setVisibility(col.id ?? '', !visibility[col.id ?? '']);
|
|
20
20
|
} }) }), _jsx("div", { className: "ml-3 text-sm leading-6", children: _jsx("label", { htmlFor: col.id, className: "font-medium text-gray-900 dark:text-gray-200", children: col.header }) })] }, col.id))) }) }) }) }) })] }) }));
|
|
21
21
|
};
|
package/dist/Table/index.d.ts
CHANGED
|
@@ -24,6 +24,7 @@ interface DummyRow {
|
|
|
24
24
|
isBottomSubRow?: boolean;
|
|
25
25
|
}
|
|
26
26
|
export type Row = DataRow | DummyRow;
|
|
27
|
+
export declare const isDummyRow: (row: Row) => row is DummyRow;
|
|
27
28
|
interface TableProps {
|
|
28
29
|
data?: Uint8Array;
|
|
29
30
|
total: bigint;
|
|
@@ -36,7 +37,12 @@ interface TableProps {
|
|
|
36
37
|
isHalfScreen: boolean;
|
|
37
38
|
unit?: string;
|
|
38
39
|
}
|
|
40
|
+
export type ColumnName = 'flat' | 'flatPercentage' | 'flatDiff' | 'flatDiffPercentage' | 'cumulative' | 'cumulativePercentage' | 'cumulativeDiff' | 'cumulativeDiffPercentage' | 'name' | 'functionSystemName' | 'functionFileName' | 'mappingFile';
|
|
41
|
+
export declare const getPercentageString: (value: bigint | number, total: bigint | number) => string;
|
|
42
|
+
export declare const getRatioString: (value: bigint | number, total: bigint, filtered: bigint) => string;
|
|
43
|
+
export declare const possibleColumns: string[];
|
|
39
44
|
export declare const Table: React.NamedExoticComponent<TableProps>;
|
|
45
|
+
export declare const addPlusSign: (num: string) => string;
|
|
40
46
|
export declare const RowName: (mappingFileColumn: Vector | null, locationAddressColumn: Vector | null, functionNameColumn: Vector | null, row: number) => string;
|
|
41
47
|
export default Table;
|
|
42
48
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAU/E,OAAO,EAAQ,MAAM,EAAgC,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/Table/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAA0D,MAAM,OAAO,CAAC;AAU/E,OAAO,EAAQ,MAAM,EAAgC,MAAM,cAAc,CAAC;AAW1E,OAAO,EAAC,WAAW,EAAC,MAAM,eAAe,CAAC;AAmB1C,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW,EAAE,MAAM,CAAC;IACpB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,OAAO,EAAE,CAAC;IACpB,OAAO,CAAC,EAAE,GAAG,EAAE,CAAC;IAChB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,UAAU,QAAQ;IAChB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,GAAG,GAAG,OAAO,GAAG,QAAQ,CAAC;AAErC,eAAO,MAAM,UAAU,QAAS,GAAG,KAAG,GAAG,IAAI,QAE5C,CAAC;AAIF,UAAU,UAAU;IAClB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,MAAM,KAAK,IAAI,CAAC;IACjD,gBAAgB,CAAC,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,GAAG,CAAC,OAAO,KAAK,IAAI,CAAC;IACxD,YAAY,EAAE,OAAO,CAAC;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,UAAU,GAClB,MAAM,GACN,gBAAgB,GAChB,UAAU,GACV,oBAAoB,GACpB,YAAY,GACZ,sBAAsB,GACtB,gBAAgB,GAChB,0BAA0B,GAC1B,MAAM,GACN,oBAAoB,GACpB,kBAAkB,GAClB,aAAa,CAAC;AA4LlB,eAAO,MAAM,mBAAmB,UAAW,MAAM,GAAG,MAAM,SAAS,MAAM,GAAG,MAAM,KAAG,MAOpF,CAAC;AAEF,eAAO,MAAM,cAAc,UAAW,MAAM,GAAG,MAAM,SAAS,MAAM,YAAY,MAAM,KAAG,MAMxF,CAAC;AAEF,eAAO,MAAM,eAAe,UAa3B,CAAC;AAEF,eAAO,MAAM,KAAK,wCAoZhB,CAAC;AAEH,eAAO,MAAM,WAAW,QAAS,MAAM,KAAG,MAMzC,CAAC;AAEF,eAAO,MAAM,OAAO,sBACC,MAAM,GAAG,IAAI,yBACT,MAAM,GAAG,IAAI,sBAChB,MAAM,GAAG,IAAI,OAC5B,MAAM,KACV,MAoBF,CAAC;AAgDF,eAAe,KAAK,CAAC"}
|
package/dist/Table/index.js
CHANGED
|
@@ -17,11 +17,10 @@ import { createColumnHelper, } from '@tanstack/table-core';
|
|
|
17
17
|
import { tableFromIPC, vectorFromArray } from 'apache-arrow';
|
|
18
18
|
import cx from 'classnames';
|
|
19
19
|
import { AnimatePresence, motion } from 'framer-motion';
|
|
20
|
-
import {
|
|
20
|
+
import { Table as TableComponent, TableSkeleton, useParcaContext, useURLState, } from '@parca/components';
|
|
21
21
|
import { getLastItem, isSearchMatch, valueFormatter } from '@parca/utilities';
|
|
22
22
|
import { useProfileViewContext } from '../ProfileView/ProfileViewContext';
|
|
23
23
|
import { hexifyAddress } from '../utils';
|
|
24
|
-
import ColumnsVisibility from './ColumnsVisibility';
|
|
25
24
|
import { getTopAndBottomExpandedRowModel } from './utils/topAndBottomExpandedRowModel';
|
|
26
25
|
const FIELD_MAPPING_FILE = 'mapping_file';
|
|
27
26
|
const FIELD_LOCATION_ADDRESS = 'location_address';
|
|
@@ -34,7 +33,7 @@ const FIELD_CUMULATIVE = 'cumulative';
|
|
|
34
33
|
const FIELD_CUMULATIVE_DIFF = 'cumulative_diff';
|
|
35
34
|
const FIELD_CALLERS = 'callers';
|
|
36
35
|
const FIELD_CALLEES = 'callees';
|
|
37
|
-
const isDummyRow = (row) => {
|
|
36
|
+
export const isDummyRow = (row) => {
|
|
38
37
|
return 'size' in row;
|
|
39
38
|
};
|
|
40
39
|
let doubleClickTimer = null;
|
|
@@ -146,10 +145,40 @@ const getCalleeRows = (callees) => {
|
|
|
146
145
|
}
|
|
147
146
|
return [{ size: 3 - rows.length, message: '', isBottomSubRow: true }, ...rows];
|
|
148
147
|
};
|
|
149
|
-
export const
|
|
148
|
+
export const getPercentageString = (value, total) => {
|
|
149
|
+
if (total === 0n) {
|
|
150
|
+
return '0%';
|
|
151
|
+
}
|
|
152
|
+
const percentage = (Number(value) / Number(total)) * 100;
|
|
153
|
+
return `${percentage.toFixed(2)}%`;
|
|
154
|
+
};
|
|
155
|
+
export const getRatioString = (value, total, filtered) => {
|
|
156
|
+
if (filtered === 0n) {
|
|
157
|
+
return ` ${getPercentageString(value, total)}`;
|
|
158
|
+
}
|
|
159
|
+
return `${getPercentageString(value, total)} / ${getPercentageString(value, filtered)}`;
|
|
160
|
+
};
|
|
161
|
+
export const possibleColumns = [
|
|
162
|
+
'flat',
|
|
163
|
+
'flatPercentage',
|
|
164
|
+
'flatDiff',
|
|
165
|
+
'flatDiffPercentage',
|
|
166
|
+
'cumulative',
|
|
167
|
+
'cumulativePercentage',
|
|
168
|
+
'cumulativeDiff',
|
|
169
|
+
'cumulativeDiffPercentage',
|
|
170
|
+
'name',
|
|
171
|
+
'functionSystemName',
|
|
172
|
+
'functionFileName',
|
|
173
|
+
'mappingFile',
|
|
174
|
+
];
|
|
175
|
+
export const Table = React.memo(function Table({ data, total, filtered, profileType, loading, currentSearchString, setSearchString = () => { }, isHalfScreen, unit, }) {
|
|
150
176
|
const [dashboardItems] = useURLState('dashboard_items', {
|
|
151
177
|
alwaysReturnArray: true,
|
|
152
178
|
});
|
|
179
|
+
const [tableColumns] = useURLState('table_columns', {
|
|
180
|
+
alwaysReturnArray: true,
|
|
181
|
+
});
|
|
153
182
|
const { isDarkMode } = useParcaContext();
|
|
154
183
|
const [expanded, setExpanded] = useState({});
|
|
155
184
|
const [scrollToIndex, setScrollToIndex] = useState(undefined);
|
|
@@ -310,6 +339,17 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
|
|
|
310
339
|
mappingFile: false,
|
|
311
340
|
};
|
|
312
341
|
});
|
|
342
|
+
useEffect(() => {
|
|
343
|
+
if (Array.isArray(tableColumns)) {
|
|
344
|
+
setColumnVisibility(prevState => {
|
|
345
|
+
const newState = { ...prevState };
|
|
346
|
+
Object.keys(newState).forEach(column => {
|
|
347
|
+
newState[column] = tableColumns.includes(column);
|
|
348
|
+
});
|
|
349
|
+
return newState;
|
|
350
|
+
});
|
|
351
|
+
}
|
|
352
|
+
}, [tableColumns]);
|
|
313
353
|
const selectSpan = useCallback((span) => {
|
|
314
354
|
setSearchString(span.trim());
|
|
315
355
|
}, [setSearchString]);
|
|
@@ -359,22 +399,6 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
|
|
|
359
399
|
const enableHighlighting = useMemo(() => {
|
|
360
400
|
return currentSearchString != null && currentSearchString?.length > 0;
|
|
361
401
|
}, [currentSearchString]);
|
|
362
|
-
const clearSelection = useCallback(() => {
|
|
363
|
-
setSearchString('');
|
|
364
|
-
}, [setSearchString]);
|
|
365
|
-
useEffect(() => {
|
|
366
|
-
setActionButtons?.(_jsxs(_Fragment, { children: [_jsx(ColumnsVisibility, { columns: columns, visibility: columnVisibility, setVisibility: (id, visible) => {
|
|
367
|
-
setColumnVisibility({ ...columnVisibility, [id]: visible });
|
|
368
|
-
} }), dashboardItems.length > 1 && (_jsx(Button, { color: "neutral", onClick: clearSelection, className: "w-auto", variant: "neutral", disabled: currentSearchString === undefined || currentSearchString.length === 0, children: "Clear selection" }))] }));
|
|
369
|
-
}, [
|
|
370
|
-
dashboardItems,
|
|
371
|
-
clearSelection,
|
|
372
|
-
currentSearchString,
|
|
373
|
-
setActionButtons,
|
|
374
|
-
columns,
|
|
375
|
-
columnVisibility,
|
|
376
|
-
loading,
|
|
377
|
-
]);
|
|
378
402
|
const initialSorting = useMemo(() => {
|
|
379
403
|
return [
|
|
380
404
|
{
|
|
@@ -458,7 +482,7 @@ export const Table = React.memo(function Table({ data, total, filtered, profileT
|
|
|
458
482
|
setExpanded(newState);
|
|
459
483
|
}, CustomRowRenderer: CustomRowRenderer, scrollToIndex: scrollToIndex, estimatedRowHeight: ROW_HEIGHT }) }) }) }, "table-loaded") }));
|
|
460
484
|
});
|
|
461
|
-
const addPlusSign = (num) => {
|
|
485
|
+
export const addPlusSign = (num) => {
|
|
462
486
|
if (num.charAt(0) === '0' || num.charAt(0) === '-') {
|
|
463
487
|
return num;
|
|
464
488
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GroupByDropdown.d.ts","sourceRoot":"","sources":["../../../src/components/ActionButtons/GroupByDropdown.tsx"],"names":[],"mappings":"AAyDA,QAAA,MAAM,eAAe,gCAGlB;IACD,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,aAAa,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,KAAG,KAAK,CAAC,GAAG,CAAC,OA6Db,CAAC;AAEF,eAAe,eAAe,CAAC"}
|
|
@@ -13,7 +13,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { Menu, Transition } from '@headlessui/react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
|
-
import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '
|
|
16
|
+
import { FIELD_FUNCTION_FILE_NAME, FIELD_FUNCTION_NAME, FIELD_LABELS, FIELD_LOCATION_ADDRESS, FIELD_MAPPING_FILE, } from '../../ProfileIcicleGraph/IcicleGraphArrow';
|
|
17
17
|
const groupByOptions = [
|
|
18
18
|
{
|
|
19
19
|
value: FIELD_FUNCTION_NAME,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FilterByFunctionButton.d.ts","sourceRoot":"","sources":["../../src/components/FilterByFunctionButton.tsx"],"names":[],"mappings":"AAoBA,QAAA,MAAM,sBAAsB,QAAO,GAAG,CAAC,OAuCtC,CAAC;AAEF,eAAe,sBAAsB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ResultBox.d.ts","sourceRoot":"","sources":["../../../src/components/ShareButton/ResultBox.tsx"],"names":[],"mappings":"AAoBA,UAAU,KAAK;IACb,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAID,QAAA,MAAM,SAAS,yBAA6B,KAAK,KAAG,GAAG,CAAC,OAqCvD,CAAC;AAEF,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { QueryRequest, QueryServiceClient } from '@parca/client';
|
|
3
|
+
import { ProfileSource } from '../../ProfileSource';
|
|
4
|
+
interface Props {
|
|
5
|
+
profileSource?: ProfileSource;
|
|
6
|
+
queryClient?: QueryServiceClient;
|
|
7
|
+
queryRequest?: QueryRequest;
|
|
8
|
+
onDownloadPProf: () => void;
|
|
9
|
+
pprofdownloading: boolean;
|
|
10
|
+
profileViewExternalSubActions: React.ReactNode;
|
|
11
|
+
}
|
|
12
|
+
declare const ShareButton: ({ queryRequest, queryClient, profileSource, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, }: Props) => JSX.Element;
|
|
13
|
+
export default ShareButton;
|
|
14
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/ShareButton/index.tsx"],"names":[],"mappings":"AAaA,OAAO,KAAiB,MAAM,OAAO,CAAC;AAItC,OAAO,EAAC,YAAY,EAAE,kBAAkB,EAAC,MAAM,eAAe,CAAC;AAG/D,OAAO,EAAC,aAAa,EAAC,MAAM,qBAAqB,CAAC;AAGlD,UAAU,KAAK;IACb,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC,YAAY,CAAC,EAAE,YAAY,CAAC;IAC5B,eAAe,EAAE,MAAM,IAAI,CAAC;IAC5B,gBAAgB,EAAE,OAAO,CAAC;IAC1B,6BAA6B,EAAE,KAAK,CAAC,SAAS,CAAC;CAChD;AAkGD,QAAA,MAAM,WAAW,oHAOd,KAAK,KAAG,GAAG,CAAC,OA4Ed,CAAC;AAEF,eAAe,WAAW,CAAC"}
|
|
@@ -13,7 +13,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
|
|
|
13
13
|
// limitations under the License.
|
|
14
14
|
import { useState } from 'react';
|
|
15
15
|
import { Icon } from '@iconify/react';
|
|
16
|
-
import { Button, Modal, useGrpcMetadata } from '@parca/components';
|
|
16
|
+
import { Button, Dropdown, Modal, useGrpcMetadata } from '@parca/components';
|
|
17
17
|
import ResultBox from './ResultBox';
|
|
18
18
|
const ProfileShareModal = ({ isOpen, closeModal, queryRequest, queryClient, }) => {
|
|
19
19
|
const [isShared, setIsShared] = useState(false);
|
|
@@ -53,8 +53,31 @@ const ProfileShareModal = ({ isOpen, closeModal, queryRequest, queryClient, }) =
|
|
|
53
53
|
void handleSubmit();
|
|
54
54
|
}, disabled: loading || !isFormDataValid(), type: "submit", children: loading ? 'Sharing' : 'Share' }), error !== '' ? _jsx("p", { children: "Something went wrong please try again" }) : null] })) : (_jsxs(_Fragment, { children: [_jsx(ResultBox, { value: sharedLink, className: "mt-4" }), _jsx("div", { className: "mt-8 flex justify-center", children: _jsx(Button, { variant: "neutral", className: "w-fit", onClick: onClose, children: "Close" }) })] }))] }) }));
|
|
55
55
|
};
|
|
56
|
-
const
|
|
57
|
-
const [
|
|
58
|
-
|
|
56
|
+
const ShareButton = ({ queryRequest, queryClient, profileSource, onDownloadPProf, pprofdownloading, profileViewExternalSubActions, }) => {
|
|
57
|
+
const [showProfileShareModal, setShowProfileShareModal] = useState(false);
|
|
58
|
+
const actions = [
|
|
59
|
+
{
|
|
60
|
+
key: 'shareProfile',
|
|
61
|
+
label: 'Share profile via link',
|
|
62
|
+
onSelect: () => setShowProfileShareModal(true),
|
|
63
|
+
id: 'h-share-profile-button',
|
|
64
|
+
disabled: profileSource === undefined && queryClient === undefined && queryRequest === undefined,
|
|
65
|
+
icon: 'material-symbols-light:link',
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: 'downloadProfile',
|
|
69
|
+
label: pprofdownloading != null && pprofdownloading ? 'Downloading...' : 'Download as pprof',
|
|
70
|
+
onSelect: () => onDownloadPProf(),
|
|
71
|
+
id: 'h-download-pprof',
|
|
72
|
+
disabled: pprofdownloading,
|
|
73
|
+
icon: 'material-symbols:download',
|
|
74
|
+
},
|
|
75
|
+
];
|
|
76
|
+
return (_jsx(_Fragment, { children: profileViewExternalSubActions != null ? (_jsx(_Fragment, { children: _jsxs(Button, { className: "gap-2", variant: "neutral", onClick: e => {
|
|
77
|
+
e.preventDefault();
|
|
78
|
+
onDownloadPProf();
|
|
79
|
+
}, disabled: pprofdownloading, id: "h-download-pprof", children: [pprofdownloading != null && pprofdownloading ? 'Downloading...' : 'Download pprof', _jsx(Icon, { icon: "material-symbols:download", width: 20 })] }) })) : (_jsxs(_Fragment, { children: [_jsxs(Dropdown, { dropdownWidth: "w-48", element: _jsxs(Button, { variant: "neutral", children: ["Share", _jsx(Icon, { icon: "material-symbols:share", className: "h-5 w-5 ml-2" })] }), children: [_jsx("span", { className: "text-xs text-gray-400 capitalize px-2", children: "actions" }), actions.map(item => (_jsx(Dropdown.Item, { onSelect: item.onSelect, children: _jsxs("div", { id: item.id, className: "flex items-center", children: [_jsx("span", { children: item.label }), _jsx(Icon, { icon: item.icon, className: "ml-2 h-4 w-4" })] }) }, item.key)))] }), profileSource !== undefined &&
|
|
80
|
+
queryClient !== undefined &&
|
|
81
|
+
queryRequest !== undefined && (_jsx(ProfileShareModal, { isOpen: showProfileShareModal, closeModal: () => setShowProfileShareModal(false), queryRequest: queryRequest, queryClient: queryClient }))] })) }));
|
|
59
82
|
};
|
|
60
|
-
export default
|
|
83
|
+
export default ShareButton;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export interface DropdownElement {
|
|
2
|
+
active: JSX.Element;
|
|
3
|
+
expanded: JSX.Element;
|
|
4
|
+
}
|
|
5
|
+
export interface DropdownItem {
|
|
6
|
+
key: string;
|
|
7
|
+
disabled?: boolean;
|
|
8
|
+
element: DropdownElement;
|
|
9
|
+
innerAction?: InnerAction;
|
|
10
|
+
}
|
|
11
|
+
export interface InnerAction {
|
|
12
|
+
text: string;
|
|
13
|
+
onClick: () => void;
|
|
14
|
+
}
|
|
15
|
+
export declare function contructItemsFromArray(items: any[]): DropdownItem[];
|
|
16
|
+
declare const Dropdown: ({ items, selectedKey, onSelection, placeholder, width, className, loading, primary, disabled, icon, id, }: {
|
|
17
|
+
items: DropdownItem[];
|
|
18
|
+
selectedKey: string | undefined;
|
|
19
|
+
onSelection: (value: string) => void;
|
|
20
|
+
placeholder?: string;
|
|
21
|
+
width?: number;
|
|
22
|
+
className?: string;
|
|
23
|
+
loading?: boolean;
|
|
24
|
+
primary?: boolean;
|
|
25
|
+
disabled?: boolean;
|
|
26
|
+
icon?: JSX.Element;
|
|
27
|
+
id?: string;
|
|
28
|
+
}) => JSX.Element;
|
|
29
|
+
export default Dropdown;
|
|
30
|
+
//# sourceMappingURL=Dropdown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/ViewSelector/Dropdown.tsx"],"names":[],"mappings":"AAqBA,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,GAAG,CAAC,OAAO,CAAC;IACpB,QAAQ,EAAE,GAAG,CAAC,OAAO,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;CAC3B;AAED,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,GAAG,EAAE,GAAG,YAAY,EAAE,CAMnE;AAED,QAAA,MAAM,QAAQ,8GAYX;IACD,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,IAAI,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC;IACnB,EAAE,CAAC,EAAE,MAAM,CAAC;CACb,KAAG,GAAG,CAAC,OA4GP,CAAC;AAEF,eAAe,QAAQ,CAAC"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
// Copyright 2022 The Parca Authors
|
|
3
|
+
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
// you may not use this file except in compliance with the License.
|
|
5
|
+
// You may obtain a copy of the License at
|
|
6
|
+
//
|
|
7
|
+
// http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
//
|
|
9
|
+
// Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
// See the License for the specific language governing permissions and
|
|
13
|
+
// limitations under the License.
|
|
14
|
+
import { Fragment } from 'react';
|
|
15
|
+
import { Listbox, Transition } from '@headlessui/react';
|
|
16
|
+
import { Icon } from '@iconify/react';
|
|
17
|
+
import cx from 'classnames';
|
|
18
|
+
import { Button, useParcaContext } from '@parca/components';
|
|
19
|
+
export function contructItemsFromArray(items) {
|
|
20
|
+
return items.map(item => ({
|
|
21
|
+
key: item.key,
|
|
22
|
+
element: { active: _jsx(_Fragment, { children: item.label }), expanded: _jsx(_Fragment, { children: item.label }) },
|
|
23
|
+
innerAction: item.innerAction,
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
const Dropdown = ({ items, selectedKey, onSelection, placeholder, width, className = '', loading, primary = false, disabled = false, icon, id, }) => {
|
|
27
|
+
const selection = items.find(v => v.key === selectedKey) ?? {
|
|
28
|
+
key: selectedKey,
|
|
29
|
+
element: { active: _jsx(_Fragment, { children: selectedKey }), expanded: _jsx(_Fragment, { children: selectedKey }) },
|
|
30
|
+
};
|
|
31
|
+
const { loader } = useParcaContext();
|
|
32
|
+
const styles = 'relative border rounded-md shadow-sm px-4 py-2 text-left cursor-default focus:outline-none focus:ring-1 items-center focus:ring-indigo-500 focus:border-indigo-500 text-sm flex gap-2 flex items-center justify-between';
|
|
33
|
+
const defaultStyles = 'bg-white dark:bg-gray-900 dark:border-gray-600';
|
|
34
|
+
const primaryStyles = 'text-gray-100 dark:gray-900 bg-indigo-600 border-indigo-500 font-medium py-2 px-4';
|
|
35
|
+
return (_jsx(Listbox, { value: selectedKey, onChange: onSelection, children: ({ open }) => (_jsxs("div", { className: "relative", children: [_jsx("div", { id: id, children: _jsxs(Listbox.Button, { className: cx(styles, width !== undefined ? `w-${width}` : 'w-full', disabled ? 'cursor-not-allowed opacity-50 pointer-events-none' : '', primary ? primaryStyles : defaultStyles, { [className]: className.length > 0 }), children: [_jsx("div", { className: cx(icon != null ? '' : 'block overflow-x-hidden text-ellipsis'), children: selection?.key !== '' ? selection.element.active : placeholder }), _jsx("div", { className: cx(icon != null ? '' : 'pointer-events-none text-gray-400'), children: icon ?? _jsx(Icon, { icon: "heroicons:chevron-up-down-20-solid", "aria-hidden": "true" }) })] }) }), _jsx(Transition, { show: open, as: Fragment, leave: "transition ease-in duration-100", leaveFrom: "opacity-100", leaveTo: "opacity-0", children: _jsx(Listbox.Options, { className: "absolute w-[246px] right-0 z-50 mt-1 max-h-[50vh] overflow-auto rounded-md bg-gray-50 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none dark:border-gray-600 dark:bg-gray-900 dark:ring-white dark:ring-opacity-20 sm:text-sm", children: loading === true ? (_jsx("div", { className: "w-[270px]", children: loader })) : (items.length > 0 &&
|
|
36
|
+
items.map(option => (_jsx(Listbox.Option, { id: `h-select-option-${option.key}`, disabled: option.disabled ?? false, className: ({ active }) => cx(active && 'bg-indigo-600 text-white', 'relative flex cursor-default select-none py-2 px-3'), value: option.key, children: ({ selected, active, disabled }) => (_jsxs("div", { className: "flex items-center w-full justify-between", children: [_jsx("div", { className: "flex items-center", children: _jsx("span", { className: cx(selected ? 'font-semibold' : 'font-normal', disabled && 'opacity-50'), children: option.element.expanded }) }), option.innerAction !== undefined && (_jsxs(Button, { variant: "neutral", className: "p-[6px]", onClick: e => {
|
|
37
|
+
e.stopPropagation();
|
|
38
|
+
option.innerAction?.onClick();
|
|
39
|
+
}, children: [option.innerAction.text, option.innerAction.text === 'Add Panel' && (_jsx(Icon, { icon: "ic:baseline-plus", className: "w-[14px] h-[14px] ml-2" }))] })), selected ? (_jsx("span", { className: cx(active ? 'text-white' : 'text-indigo-600', 'absolute inset-y-0 right-0 flex items-center pr-4'), children: _jsx(Icon, { icon: "heroicons:check-20-solid", "aria-hidden": "true" }) })) : null] })) }, option.key)))) }) })] })) }));
|
|
40
|
+
};
|
|
41
|
+
export default Dropdown;
|