@parca/profile 0.16.103 → 0.16.105

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 (37) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/Callgraph/index.d.ts +1 -0
  3. package/dist/GraphTooltip/index.d.ts +1 -0
  4. package/dist/IcicleGraph.d.ts +1 -0
  5. package/dist/IcicleGraph.js +1 -2
  6. package/dist/MatchersInput/SuggestionItem.d.ts +1 -0
  7. package/dist/MatchersInput/SuggestionsList.d.ts +1 -0
  8. package/dist/MatchersInput/index.d.ts +1 -0
  9. package/dist/MetricsCircle/index.d.ts +1 -0
  10. package/dist/MetricsGraph/index.d.ts +1 -0
  11. package/dist/MetricsSeries/index.d.ts +1 -0
  12. package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts +1 -0
  13. package/dist/ProfileExplorer/ProfileExplorerSingle.d.ts +1 -0
  14. package/dist/ProfileExplorer/index.d.ts +1 -0
  15. package/dist/ProfileIcicleGraph/index.d.ts +3 -1
  16. package/dist/ProfileIcicleGraph/index.js +2 -2
  17. package/dist/ProfileMetricsGraph/index.d.ts +1 -0
  18. package/dist/ProfileSelector/CompareButton.d.ts +1 -0
  19. package/dist/ProfileSelector/MergeButton.d.ts +1 -0
  20. package/dist/ProfileSelector/index.d.ts +1 -0
  21. package/dist/ProfileSource.d.ts +1 -0
  22. package/dist/ProfileTypeSelector/index.d.ts +1 -0
  23. package/dist/ProfileView/FilterByFunctionButton.d.ts +1 -0
  24. package/dist/ProfileView/ViewSelector.d.ts +1 -0
  25. package/dist/ProfileView/index.d.ts +1 -0
  26. package/dist/ProfileView/index.js +4 -4
  27. package/dist/ProfileViewWithData.d.ts +1 -0
  28. package/dist/TopTable/index.d.ts +3 -1
  29. package/dist/TopTable/index.js +2 -2
  30. package/dist/components/DiffLegend.d.ts +1 -0
  31. package/dist/components/ProfileShareButton/ResultBox.d.ts +1 -0
  32. package/dist/components/ProfileShareButton/index.d.ts +1 -0
  33. package/package.json +4 -4
  34. package/src/IcicleGraph.tsx +7 -2
  35. package/src/ProfileIcicleGraph/index.tsx +5 -1
  36. package/src/ProfileView/index.tsx +7 -3
  37. package/src/TopTable/index.tsx +8 -2
package/CHANGELOG.md CHANGED
@@ -3,6 +3,14 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.16.105](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.104...@parca/profile@0.16.105) (2023-02-02)
7
+
8
+ **Note:** Version bump only for package @parca/profile
9
+
10
+ ## [0.16.104](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.103...@parca/profile@0.16.104) (2023-01-27)
11
+
12
+ **Note:** Version bump only for package @parca/profile
13
+
6
14
  ## [0.16.103](https://github.com/parca-dev/parca/compare/@parca/profile@0.16.102...@parca/profile@0.16.103) (2023-01-27)
7
15
 
8
16
  **Note:** Version bump only for package @parca/profile
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { Callgraph as CallgraphType } from '@parca/client';
2
3
  export interface Props {
3
4
  graph: CallgraphType;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { CallgraphNode, FlamegraphNode, FlamegraphNodeMeta, FlamegraphRootNode } from '@parca/client';
2
3
  import { Function as ParcaFunction, Location, Mapping } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
3
4
  interface GraphTooltipProps {
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { Flamegraph, FlamegraphNode, FlamegraphRootNode } from '@parca/client';
2
3
  import { Mapping, Function as ParcaFunction, Location } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
3
4
  interface IcicleGraphProps {
@@ -28,12 +28,11 @@ import { throttle } from 'lodash';
28
28
  import { pointer } from 'd3-selection';
29
29
  import { scaleLinear } from 'd3-scale';
30
30
  import GraphTooltip from './GraphTooltip';
31
- import { diffColor, getLastItem, isSearchMatch, selectQueryParam } from '@parca/functions';
31
+ import { diffColor, getLastItem, isSearchMatch, selectQueryParam, useURLState, } from '@parca/functions';
32
32
  import { selectDarkMode, useAppSelector } from '@parca/store';
33
33
  import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
34
34
  import { Button } from '@parca/components';
35
35
  import { hexifyAddress } from './utils';
36
- import { useURLState } from '@parca/functions';
37
36
  var RowHeight = 26;
38
37
  var icicleRectStyles = {
39
38
  cursor: 'pointer',
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  interface Props {
2
3
  isHighlighted: boolean;
3
4
  onHighlight: () => void;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  export declare class Suggestion {
2
3
  type: string;
3
4
  typeahead: string;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { Query } from '@parca/parser';
2
3
  import { LabelsResponse, QueryServiceClient } from '@parca/client';
3
4
  interface MatchersInputProps {
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  interface MetricsCircleProps {
2
3
  cx: number;
3
4
  cy: number;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { SingleProfileSelection } from '..';
2
3
  import { MetricsSeries as MetricsSeriesPb, Label } from '@parca/client';
3
4
  import { DateTimeRange } from '@parca/components';
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import * as d3 from 'd3';
2
3
  interface MetricsSeriesProps {
3
4
  data: any;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { NavigateFunction } from '@parca/functions';
2
3
  import { QueryServiceClient } from '@parca/client';
3
4
  import { ProfileSelection } from '..';
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { NavigateFunction } from '@parca/functions';
2
3
  import { QueryServiceClient } from '@parca/client';
3
4
  import { ProfileSelection } from '..';
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { QueryServiceClient } from '@parca/client';
2
3
  import { NavigateFunction } from '@parca/functions';
3
4
  interface ProfileExplorerProps {
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { Flamegraph } from '@parca/client';
2
3
  export type ResizeHandler = (width: number, height: number) => void;
3
4
  interface ProfileIcicleGraphProps {
@@ -7,6 +8,7 @@ interface ProfileIcicleGraphProps {
7
8
  curPath: string[] | [];
8
9
  setNewCurPath: (path: string[]) => void;
9
10
  onContainerResize?: ResizeHandler;
11
+ loading: boolean;
10
12
  }
11
- declare const ProfileIcicleGraph: ({ graph, curPath, setNewCurPath, sampleUnit, onContainerResize, }: ProfileIcicleGraphProps) => JSX.Element;
13
+ declare const ProfileIcicleGraph: ({ graph, curPath, setNewCurPath, sampleUnit, onContainerResize, loading, }: ProfileIcicleGraphProps) => JSX.Element;
12
14
  export default ProfileIcicleGraph;
@@ -17,7 +17,7 @@ import { selectQueryParam } from '@parca/functions';
17
17
  import { useEffect, useMemo } from 'react';
18
18
  var numberFormatter = new Intl.NumberFormat('en-US');
19
19
  var ProfileIcicleGraph = function (_a) {
20
- var graph = _a.graph, curPath = _a.curPath, setNewCurPath = _a.setNewCurPath, sampleUnit = _a.sampleUnit, onContainerResize = _a.onContainerResize;
20
+ var graph = _a.graph, curPath = _a.curPath, setNewCurPath = _a.setNewCurPath, sampleUnit = _a.sampleUnit, onContainerResize = _a.onContainerResize, loading = _a.loading;
21
21
  var compareMode = selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true';
22
22
  var _b = useContainerDimensions(), ref = _b.ref, dimensions = _b.dimensions;
23
23
  useEffect(function () {
@@ -45,7 +45,7 @@ var ProfileIcicleGraph = function (_a) {
45
45
  if (graph === undefined)
46
46
  return _jsx("div", { children: "no data..." });
47
47
  var total = graph.total;
48
- if (parseFloat(total) === 0)
48
+ if (parseFloat(total) === 0 && !loading)
49
49
  return _jsx(_Fragment, { children: "Profile has no samples" });
50
50
  return (_jsxs(_Fragment, { children: [compareMode && _jsx(DiffLegend, {}), trimDifference > BigInt(0) ? (_jsxs("p", __assign({ className: "my-2 text-sm" }, { children: ["Showing ", formattedTotal, "(", trimmedPercentage, "%) out of ", formattedUntrimmedTotal, " samples"] }))) : null, _jsx("div", __assign({ ref: ref }, { children: _jsx(IcicleGraph, { width: dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, graph: graph, curPath: curPath, setCurPath: setNewCurPath, sampleUnit: sampleUnit }) }))] }));
51
51
  };
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { ProfileSelection } from '..';
2
3
  import { QueryServiceClient, QueryRangeResponse } from '@parca/client';
3
4
  import { RpcError } from '@protobuf-ts/runtime-rpc';
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  declare const CompareButton: ({ disabled, onClick, }: {
2
3
  disabled: boolean;
3
4
  onClick: () => void;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  declare const MergeButton: ({ disabled, onClick, }: {
2
3
  disabled: boolean;
3
4
  onClick: () => void;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { QueryServiceClient, ProfileTypesResponse } from '@parca/client';
2
3
  import { RpcError } from '@protobuf-ts/runtime-rpc';
3
4
  import { ProfileSelection } from '..';
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { ProfileType } from '@parca/parser';
2
3
  import { Label, QueryRequest, ProfileDiffSelection } from '@parca/client';
3
4
  export interface ProfileSource {
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { ProfileType, ProfileTypesResponse } from '@parca/client';
2
3
  import { RpcError } from '@protobuf-ts/runtime-rpc';
3
4
  interface WellKnownProfile {
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { NavigateFunction } from '@parca/functions';
2
3
  declare const FilterByFunctionButton: ({ navigateTo, }: {
3
4
  navigateTo: NavigateFunction | undefined;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { NavigateFunction } from '@parca/functions';
2
3
  interface Props {
3
4
  position: number;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { QueryServiceClient, Flamegraph, Top, Callgraph as CallgraphType } from '@parca/client';
2
3
  import { ResizeHandler } from '../ProfileIcicleGraph';
3
4
  import { ProfileSource } from '../ProfileSource';
@@ -101,13 +101,13 @@ export var ProfileView = function (_a) {
101
101
  var type = _a.type, isHalfScreen = _a.isHalfScreen;
102
102
  switch (type) {
103
103
  case 'icicle': {
104
- return (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null ? (_jsx(Profiler, __assign({ id: "icicleGraph", onRender: perf === null || perf === void 0 ? void 0 : perf.onRender }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit, onContainerResize: onFlamegraphContainerResize }) }))) : (_jsx(_Fragment, {}));
104
+ return (flamegraphData === null || flamegraphData === void 0 ? void 0 : flamegraphData.data) != null ? (_jsx(Profiler, __assign({ id: "icicleGraph", onRender: perf === null || perf === void 0 ? void 0 : perf.onRender }, { children: _jsx(ProfileIcicleGraph, { curPath: curPath, setNewCurPath: setNewCurPath, graph: flamegraphData.data, sampleUnit: sampleUnit, onContainerResize: onFlamegraphContainerResize, loading: flamegraphData.loading }) }))) : (_jsx(_Fragment, {}));
105
105
  }
106
106
  case 'callgraph': {
107
107
  return (callgraphData === null || callgraphData === void 0 ? void 0 : callgraphData.data) != null && (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) !== undefined ? (_jsx(Callgraph, { graph: callgraphData.data, sampleUnit: sampleUnit, width: isHalfScreen ? (dimensions === null || dimensions === void 0 ? void 0 : dimensions.width) / 2 : dimensions === null || dimensions === void 0 ? void 0 : dimensions.width, colorRange: colorRange })) : (_jsx(_Fragment, {}));
108
108
  }
109
109
  case 'table': {
110
- return topTableData != null ? (_jsx(TopTable, { data: topTableData.data, sampleUnit: sampleUnit, navigateTo: navigateTo })) : (_jsx(_Fragment, {}));
110
+ return topTableData != null ? (_jsx(TopTable, { loading: topTableData.loading, data: topTableData.data, sampleUnit: sampleUnit, navigateTo: navigateTo })) : (_jsx(_Fragment, {}));
111
111
  }
112
112
  default: {
113
113
  return _jsx(_Fragment, {});
@@ -128,10 +128,10 @@ export var ProfileView = function (_a) {
128
128
  setDashboardItems(newDashboardItems);
129
129
  }
130
130
  };
131
- return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "py-3" }, { children: _jsx(Card, { children: _jsxs(Card.Body, { children: [_jsxs("div", __assign({ className: "flex py-3 w-full" }, { children: [_jsxs("div", __assign({ className: "w-2/5 flex space-x-4" }, { children: [_jsxs("div", __assign({ className: "flex space-x-1" }, { children: [profileSource != null && queryClient != null ? (_jsx(ProfileShareButton, { queryRequest: profileSource.QueryRequest(), queryClient: queryClient, disabled: isLoading })) : null, _jsx(Button, __assign({ color: "neutral", onClick: function (e) {
131
+ return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "py-3" }, { children: _jsx(Card, { children: _jsxs(Card.Body, { children: [_jsxs("div", __assign({ className: "flex py-3 w-full" }, { children: [_jsxs("div", __assign({ className: "w-2/5 flex space-x-4" }, { children: [_jsxs("div", __assign({ className: "flex space-x-1" }, { children: [profileSource != null && queryClient != null ? (_jsx(ProfileShareButton, { queryRequest: profileSource.QueryRequest(), queryClient: queryClient })) : null, _jsx(Button, __assign({ color: "neutral", onClick: function (e) {
132
132
  e.preventDefault();
133
133
  onDownloadPProf();
134
- }, disabled: isLoading }, { children: "Download pprof" }))] })), _jsx(FilterByFunctionButton, { navigateTo: navigateTo })] })), _jsx("div", __assign({ className: "flex ml-auto gap-2" }, { children: _jsx(ViewSelector, { defaultValue: "", navigateTo: navigateTo, position: -1, placeholderText: "Add panel...", primary: true, addView: true, disabled: isMultiPanelView || dashboardItems.length < 1 }) }))] })), isLoaderVisible ? (_jsx(_Fragment, { children: loader })) : (_jsx(DragDropContext, __assign({ onDragEnd: onDragEnd }, { children: _jsx("div", __assign({ className: "w-full", ref: ref }, { children: _jsx(Droppable, __assign({ droppableId: "droppable", direction: "horizontal" }, { children: function (provided) { return (_jsx("div", __assign({ ref: provided.innerRef, className: "flex space-x-4 justify-between w-full" }, provided.droppableProps, { children: dashboardItems.map(function (dashboardItem, index) {
134
+ } }, { children: "Download pprof" }))] })), _jsx(FilterByFunctionButton, { navigateTo: navigateTo })] })), _jsx("div", __assign({ className: "flex ml-auto gap-2" }, { children: _jsx(ViewSelector, { defaultValue: "", navigateTo: navigateTo, position: -1, placeholderText: "Add panel...", primary: true, addView: true, disabled: isMultiPanelView || dashboardItems.length < 1 }) }))] })), isLoaderVisible ? (_jsx(_Fragment, { children: loader })) : (_jsx(DragDropContext, __assign({ onDragEnd: onDragEnd }, { children: _jsx("div", __assign({ className: "w-full", ref: ref }, { children: _jsx(Droppable, __assign({ droppableId: "droppable", direction: "horizontal" }, { children: function (provided) { return (_jsx("div", __assign({ ref: provided.innerRef, className: "flex space-x-4 justify-between w-full" }, provided.droppableProps, { children: dashboardItems.map(function (dashboardItem, index) {
135
135
  return (_jsx(Draggable, __assign({ draggableId: dashboardItem, index: index, isDragDisabled: !isMultiPanelView }, { children: function (provided, snapshot) { return (_createElement("div", __assign({ ref: provided.innerRef }, provided.draggableProps, { key: dashboardItem, className: cx('border dark:bg-gray-700 rounded border-gray-300 dark:border-gray-500 p-3', isMultiPanelView ? 'w-1/2' : 'w-full', snapshot.isDragging ? 'bg-gray-200' : 'bg-white') }),
136
136
  _jsxs("div", __assign({ className: "w-full flex justify-end pb-2" }, { children: [_jsxs("div", __assign({ className: "w-full flex justify-between" }, { children: [_jsx("div", __assign({ className: cx(isMultiPanelView ? 'visible' : 'invisible', 'flex items-center') }, provided.dragHandleProps, { children: _jsx(Icon, { className: "text-xl", icon: "material-symbols:drag-indicator" }) })), _jsx(ViewSelector, { defaultValue: dashboardItem, navigateTo: navigateTo, position: index })] })), isMultiPanelView && (_jsx("button", __assign({ type: "button", onClick: function () { return handleClosePanel(dashboardItem); }, className: "pl-2" }, { children: _jsx(CloseIcon, {}) })))] })),
137
137
  getDashboardItemByType({
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { QueryServiceClient } from '@parca/client';
2
3
  import { ProfileSource } from './ProfileSource';
3
4
  import { NavigateFunction } from '@parca/functions';
@@ -1,11 +1,13 @@
1
+ /// <reference types="react" />
1
2
  import { NavigateFunction } from '@parca/functions';
2
3
  import { TopNodeMeta, Top } from '@parca/client';
3
4
  import '../TopTable.styles.css';
4
5
  interface TopTableProps {
6
+ loading: boolean;
5
7
  data?: Top;
6
8
  sampleUnit: string;
7
9
  navigateTo?: NavigateFunction;
8
10
  }
9
11
  export declare const RowLabel: (meta: TopNodeMeta | undefined) => string;
10
- export declare const TopTable: ({ data: top, sampleUnit: unit, navigateTo }: TopTableProps) => JSX.Element;
12
+ export declare const TopTable: ({ data: top, sampleUnit: unit, navigateTo, loading, }: TopTableProps) => JSX.Element;
11
13
  export default TopTable;
@@ -50,7 +50,7 @@ var addPlusSign = function (num) {
50
50
  };
51
51
  export var TopTable = function (_a) {
52
52
  var _b;
53
- var top = _a.data, unit = _a.sampleUnit, navigateTo = _a.navigateTo;
53
+ var top = _a.data, unit = _a.sampleUnit, navigateTo = _a.navigateTo, loading = _a.loading;
54
54
  var router = parseParams(window.location.search);
55
55
  var currentSearchString = selectQueryParam('search_string');
56
56
  var compareMode = Boolean(selectQueryParam('compare_a')) && Boolean(selectQueryParam('compare_b'));
@@ -128,7 +128,7 @@ export var TopTable = function (_a) {
128
128
  return [{ id: compareMode ? 'diff' : 'cumulative', desc: true }];
129
129
  }, [compareMode]);
130
130
  var total = top != null ? top.list.length : 0;
131
- if (total === 0)
131
+ if (total === 0 && !loading)
132
132
  return _jsx(_Fragment, { children: "Profile has no samples" });
133
133
  return (_jsx(_Fragment, { children: _jsx("div", __assign({ className: "w-full font-robotoMono h-[80vh] overflow-scroll" }, { children: _jsx(Table, { data: (_b = top === null || top === void 0 ? void 0 : top.list) !== null && _b !== void 0 ? _b : [], columns: columns, initialSorting: initialSorting, onRowClick: onRowClick, enableHighlighting: enableHighlighting, shouldHighlightRow: shouldHighlightRow }) })) }));
134
134
  };
@@ -1,2 +1,3 @@
1
+ /// <reference types="react" />
1
2
  declare const DiffLegend: () => JSX.Element;
2
3
  export default DiffLegend;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  interface Props {
2
3
  value: string;
3
4
  className?: string;
@@ -1,3 +1,4 @@
1
+ /// <reference types="react" />
1
2
  import { QueryRequest, QueryServiceClient } from '@parca/client';
2
3
  interface Props {
3
4
  queryRequest: QueryRequest;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parca/profile",
3
- "version": "0.16.103",
3
+ "version": "0.16.105",
4
4
  "description": "Profile viewing libraries",
5
5
  "dependencies": {
6
6
  "@parca/client": "^0.16.62",
@@ -14,7 +14,7 @@
14
14
  "d3-scale": "^4.0.2",
15
15
  "d3-selection": "3.0.0",
16
16
  "graphviz-wasm": "3.0.0",
17
- "konva": "8.4.1",
17
+ "konva": "8.4.2",
18
18
  "react-beautiful-dnd": "^13.1.1",
19
19
  "react-copy-to-clipboard": "^5.1.0",
20
20
  "react-cytoscapejs": "1.2.1",
@@ -27,7 +27,7 @@
27
27
  "@types/react-copy-to-clipboard": "5.0.4"
28
28
  },
29
29
  "resolutions": {
30
- "konva": "8.4.1"
30
+ "konva": "8.4.2"
31
31
  },
32
32
  "main": "dist/index.js",
33
33
  "scripts": {
@@ -44,5 +44,5 @@
44
44
  "access": "public",
45
45
  "registry": "https://registry.npmjs.org/"
46
46
  },
47
- "gitHead": "483e2f35e6cc346a0eef07586194e79cd0885e59"
47
+ "gitHead": "453c1e45d742e4f815eb34e4fa542ae691d23ba5"
48
48
  }
@@ -26,12 +26,17 @@ import {
26
26
  } from '@parca/client/dist/parca/metastore/v1alpha1/metastore';
27
27
  import type {HoveringNode} from './GraphTooltip';
28
28
  import GraphTooltip from './GraphTooltip';
29
- import {diffColor, getLastItem, isSearchMatch, selectQueryParam} from '@parca/functions';
29
+ import {
30
+ diffColor,
31
+ getLastItem,
32
+ isSearchMatch,
33
+ selectQueryParam,
34
+ useURLState,
35
+ } from '@parca/functions';
30
36
  import {selectDarkMode, useAppSelector} from '@parca/store';
31
37
  import useIsShiftDown from '@parca/components/src/hooks/useIsShiftDown';
32
38
  import {Button} from '@parca/components';
33
39
  import {hexifyAddress} from './utils';
34
- import {useURLState} from '@parca/functions';
35
40
 
36
41
  interface IcicleGraphProps {
37
42
  graph: Flamegraph;
@@ -30,6 +30,7 @@ interface ProfileIcicleGraphProps {
30
30
  curPath: string[] | [];
31
31
  setNewCurPath: (path: string[]) => void;
32
32
  onContainerResize?: ResizeHandler;
33
+ loading: boolean;
33
34
  }
34
35
 
35
36
  const ProfileIcicleGraph = ({
@@ -38,6 +39,7 @@ const ProfileIcicleGraph = ({
38
39
  setNewCurPath,
39
40
  sampleUnit,
40
41
  onContainerResize,
42
+ loading,
41
43
  }: ProfileIcicleGraphProps): JSX.Element => {
42
44
  const compareMode: boolean =
43
45
  selectQueryParam('compare_a') === 'true' && selectQueryParam('compare_b') === 'true';
@@ -71,8 +73,10 @@ const ProfileIcicleGraph = ({
71
73
  }, [graph]);
72
74
 
73
75
  if (graph === undefined) return <div>no data...</div>;
76
+
74
77
  const total = graph.total;
75
- if (parseFloat(total) === 0) return <>Profile has no samples</>;
78
+
79
+ if (parseFloat(total) === 0 && !loading) return <>Profile has no samples</>;
76
80
 
77
81
  return (
78
82
  <>
@@ -157,6 +157,7 @@ export const ProfileView = ({
157
157
  graph={flamegraphData.data}
158
158
  sampleUnit={sampleUnit}
159
159
  onContainerResize={onFlamegraphContainerResize}
160
+ loading={flamegraphData.loading}
160
161
  />
161
162
  </Profiler>
162
163
  ) : (
@@ -177,7 +178,12 @@ export const ProfileView = ({
177
178
  }
178
179
  case 'table': {
179
180
  return topTableData != null ? (
180
- <TopTable data={topTableData.data} sampleUnit={sampleUnit} navigateTo={navigateTo} />
181
+ <TopTable
182
+ loading={topTableData.loading}
183
+ data={topTableData.data}
184
+ sampleUnit={sampleUnit}
185
+ navigateTo={navigateTo}
186
+ />
181
187
  ) : (
182
188
  <></>
183
189
  );
@@ -220,7 +226,6 @@ export const ProfileView = ({
220
226
  <ProfileShareButton
221
227
  queryRequest={profileSource.QueryRequest()}
222
228
  queryClient={queryClient}
223
- disabled={isLoading}
224
229
  />
225
230
  ) : null}
226
231
 
@@ -230,7 +235,6 @@ export const ProfileView = ({
230
235
  e.preventDefault();
231
236
  onDownloadPProf();
232
237
  }}
233
- disabled={isLoading}
234
238
  >
235
239
  Download pprof
236
240
  </Button>
@@ -31,6 +31,7 @@ import {hexifyAddress} from '../utils';
31
31
  import '../TopTable.styles.css';
32
32
 
33
33
  interface TopTableProps {
34
+ loading: boolean;
34
35
  data?: Top;
35
36
  sampleUnit: string;
36
37
  navigateTo?: NavigateFunction;
@@ -62,7 +63,12 @@ const addPlusSign = (num: string): string => {
62
63
  return `+${num}`;
63
64
  };
64
65
 
65
- export const TopTable = ({data: top, sampleUnit: unit, navigateTo}: TopTableProps): JSX.Element => {
66
+ export const TopTable = ({
67
+ data: top,
68
+ sampleUnit: unit,
69
+ navigateTo,
70
+ loading,
71
+ }: TopTableProps): JSX.Element => {
66
72
  const router = parseParams(window.location.search);
67
73
  const currentSearchString = selectQueryParam('search_string') as string;
68
74
  const compareMode =
@@ -166,7 +172,7 @@ export const TopTable = ({data: top, sampleUnit: unit, navigateTo}: TopTableProp
166
172
 
167
173
  const total = top != null ? top.list.length : 0;
168
174
 
169
- if (total === 0) return <>Profile has no samples</>;
175
+ if (total === 0 && !loading) return <>Profile has no samples</>;
170
176
 
171
177
  return (
172
178
  <>