@parca/profile 0.14.30 → 0.14.37
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 +34 -0
- package/package.json +5 -5
- package/src/IcicleGraph.tsx +16 -12
- package/src/ProfileIcicleGraph.tsx +1 -1
- package/src/ProfileView.tsx +10 -10
- package/src/ProfileViewWithData.tsx +3 -3
- package/src/TopTable.tsx +34 -11
- package/src/components/DiffLegend.tsx +5 -5
- package/src/components/ProfileShareButton/ResultBox.tsx +2 -2
- package/src/components/ProfileShareButton/index.tsx +6 -6
- package/src/useDelayedLoader.ts +4 -4
- package/src/useQuery.tsx +2 -2
- package/src/utils.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,40 @@
|
|
|
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.14.37](https://github.com/parca-dev/parca/compare/ui-v0.14.36...ui-v0.14.37) (2022-08-24)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @parca/profile
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [0.14.36](https://github.com/parca-dev/parca/compare/ui-v0.14.35...ui-v0.14.36) (2022-08-24)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* **ui:** enforce @typescript-eslint/explicit-function-return-type ([22a18fd](https://github.com/parca-dev/parca/commit/22a18fd3f7befef5cc175131d8c997c3967a5713))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
## 0.14.32 (2022-08-18)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
## [0.14.31](https://github.com/parca-dev/parca/compare/ui-v0.14.30...ui-v0.14.31) (2022-08-18)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
### Bug Fixes
|
|
33
|
+
|
|
34
|
+
* **ui:** address all problems reported by ESLint ([7f9c921](https://github.com/parca-dev/parca/commit/7f9c9217af49f2661a4363b9b17a9a06f1c7539b))
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
|
|
6
40
|
## [0.14.30](https://github.com/parca-dev/parca/compare/ui-v0.14.29...ui-v0.14.30) (2022-08-17)
|
|
7
41
|
|
|
8
42
|
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@parca/profile",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.37",
|
|
4
4
|
"description": "Profile viewing libraries",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@iconify/react": "^3.2.2",
|
|
7
|
-
"@parca/client": "^0.14.
|
|
8
|
-
"@parca/dynamicsize": "^0.14.
|
|
9
|
-
"@parca/parser": "^0.14.
|
|
7
|
+
"@parca/client": "^0.14.37",
|
|
8
|
+
"@parca/dynamicsize": "^0.14.36",
|
|
9
|
+
"@parca/parser": "^0.14.36",
|
|
10
10
|
"d3-scale": "^4.0.2",
|
|
11
11
|
"d3-selection": "3.0.0",
|
|
12
12
|
"react-copy-to-clipboard": "^5.1.0"
|
|
@@ -22,5 +22,5 @@
|
|
|
22
22
|
"access": "public",
|
|
23
23
|
"registry": "https://registry.npmjs.org/"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "21acf8f58da4fc28346b83a24692bcc9dabc4f46"
|
|
26
26
|
}
|
package/src/IcicleGraph.tsx
CHANGED
|
@@ -91,7 +91,7 @@ function IcicleRect({
|
|
|
91
91
|
onMouseLeave,
|
|
92
92
|
onClick,
|
|
93
93
|
curPath,
|
|
94
|
-
}: IcicleRectProps) {
|
|
94
|
+
}: IcicleRectProps): JSX.Element {
|
|
95
95
|
const currentSearchString = useAppSelector(selectSearchNodeString);
|
|
96
96
|
const isFaded = curPath.length > 0 && name !== curPath[curPath.length - 1];
|
|
97
97
|
const styles = isFaded ? fadedIcicleRectStyles : icicleRectStyles;
|
|
@@ -111,7 +111,11 @@ function IcicleRect({
|
|
|
111
111
|
height={height - 1}
|
|
112
112
|
style={{
|
|
113
113
|
opacity:
|
|
114
|
-
|
|
114
|
+
currentSearchString !== undefined &&
|
|
115
|
+
currentSearchString !== '' &&
|
|
116
|
+
!isSearchMatch(currentSearchString, name)
|
|
117
|
+
? 0.5
|
|
118
|
+
: 1,
|
|
115
119
|
fill: color,
|
|
116
120
|
}}
|
|
117
121
|
/>
|
|
@@ -130,7 +134,7 @@ export function nodeLabel(node: FlamegraphNode): string {
|
|
|
130
134
|
if (node.meta === undefined) return '<unknown>';
|
|
131
135
|
const mapping = `${
|
|
132
136
|
node.meta?.mapping?.file !== undefined && node.meta?.mapping?.file !== ''
|
|
133
|
-
? '[' + getLastItem(node.meta.mapping.file) + '] '
|
|
137
|
+
? '[' + (getLastItem(node.meta.mapping.file) ?? '') + '] '
|
|
134
138
|
: ''
|
|
135
139
|
}`;
|
|
136
140
|
if (node.meta.function?.name !== undefined && node.meta.function?.name !== '')
|
|
@@ -154,7 +158,7 @@ export function IcicleGraphNodes({
|
|
|
154
158
|
path,
|
|
155
159
|
setCurPath,
|
|
156
160
|
curPath,
|
|
157
|
-
}: IcicleGraphNodesProps) {
|
|
161
|
+
}: IcicleGraphNodesProps): JSX.Element {
|
|
158
162
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
159
163
|
|
|
160
164
|
const nodes =
|
|
@@ -185,7 +189,7 @@ export function IcicleGraphNodes({
|
|
|
185
189
|
|
|
186
190
|
const color = diffColor(diff, cumulative, isDarkMode);
|
|
187
191
|
|
|
188
|
-
const onClick = () => {
|
|
192
|
+
const onClick = (): void => {
|
|
189
193
|
setCurPath(nextPath);
|
|
190
194
|
};
|
|
191
195
|
|
|
@@ -195,8 +199,8 @@ export function IcicleGraphNodes({
|
|
|
195
199
|
? scaleLinear().domain([0, cumulative]).range([0, totalWidth])
|
|
196
200
|
: xScale;
|
|
197
201
|
|
|
198
|
-
const onMouseEnter = () => setHoveringNode(d);
|
|
199
|
-
const onMouseLeave = () => setHoveringNode(undefined);
|
|
202
|
+
const onMouseEnter = (): void => setHoveringNode(d);
|
|
203
|
+
const onMouseLeave = (): void => setHoveringNode(undefined);
|
|
200
204
|
|
|
201
205
|
return (
|
|
202
206
|
<React.Fragment key={`node-${key}`}>
|
|
@@ -246,16 +250,16 @@ export function IcicleGraphRootNode({
|
|
|
246
250
|
setHoveringNode,
|
|
247
251
|
setCurPath,
|
|
248
252
|
curPath,
|
|
249
|
-
}: IcicleGraphRootNodeProps) {
|
|
253
|
+
}: IcicleGraphRootNodeProps): JSX.Element {
|
|
250
254
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
251
255
|
|
|
252
256
|
const cumulative = parseFloat(node.cumulative);
|
|
253
257
|
const diff = parseFloat(node.diff);
|
|
254
258
|
const color = diffColor(diff, cumulative, isDarkMode);
|
|
255
259
|
|
|
256
|
-
const onClick = () => setCurPath([]);
|
|
257
|
-
const onMouseEnter = () => setHoveringNode(node);
|
|
258
|
-
const onMouseLeave = () => setHoveringNode(undefined);
|
|
260
|
+
const onClick = (): void => setCurPath([]);
|
|
261
|
+
const onMouseEnter = (): void => setHoveringNode(node);
|
|
262
|
+
const onMouseLeave = (): void => setHoveringNode(undefined);
|
|
259
263
|
const path = [];
|
|
260
264
|
|
|
261
265
|
return (
|
|
@@ -297,7 +301,7 @@ export default function IcicleGraph({
|
|
|
297
301
|
setCurPath,
|
|
298
302
|
curPath,
|
|
299
303
|
sampleUnit,
|
|
300
|
-
}: IcicleGraphProps) {
|
|
304
|
+
}: IcicleGraphProps): JSX.Element {
|
|
301
305
|
const [hoveringNode, setHoveringNode] = useState<
|
|
302
306
|
FlamegraphNode | FlamegraphRootNode | undefined
|
|
303
307
|
>();
|
|
@@ -31,7 +31,7 @@ const ProfileIcicleGraph = ({
|
|
|
31
31
|
curPath,
|
|
32
32
|
setNewCurPath,
|
|
33
33
|
sampleUnit,
|
|
34
|
-
}: ProfileIcicleGraphProps) => {
|
|
34
|
+
}: ProfileIcicleGraphProps): JSX.Element => {
|
|
35
35
|
const compareMode = useAppSelector(selectCompareMode);
|
|
36
36
|
const {ref, dimensions} = useContainerDimensions();
|
|
37
37
|
|
package/src/ProfileView.tsx
CHANGED
|
@@ -58,7 +58,7 @@ interface ProfileViewProps {
|
|
|
58
58
|
compare?: boolean;
|
|
59
59
|
}
|
|
60
60
|
|
|
61
|
-
function arrayEquals(a, b): boolean {
|
|
61
|
+
function arrayEquals<T>(a: T[], b: T[]): boolean {
|
|
62
62
|
return (
|
|
63
63
|
Array.isArray(a) &&
|
|
64
64
|
Array.isArray(b) &&
|
|
@@ -70,7 +70,7 @@ export const useProfileVisState = (): ProfileVisState => {
|
|
|
70
70
|
const router = parseParams(window.location.search);
|
|
71
71
|
const currentViewFromURL = router.currentProfileView as string;
|
|
72
72
|
const [currentView, setCurrentView] = useState<VisualizationType>(
|
|
73
|
-
(currentViewFromURL as VisualizationType)
|
|
73
|
+
(currentViewFromURL as VisualizationType) ?? 'icicle'
|
|
74
74
|
);
|
|
75
75
|
|
|
76
76
|
return {currentView, setCurrentView};
|
|
@@ -98,13 +98,13 @@ export const ProfileView = ({
|
|
|
98
98
|
|
|
99
99
|
const isLoading = useMemo(() => {
|
|
100
100
|
if (currentView === 'icicle') {
|
|
101
|
-
return
|
|
101
|
+
return Boolean(flamegraphData?.loading);
|
|
102
102
|
}
|
|
103
103
|
if (currentView === 'table') {
|
|
104
|
-
return
|
|
104
|
+
return Boolean(topTableData?.loading);
|
|
105
105
|
}
|
|
106
106
|
if (currentView === 'both') {
|
|
107
|
-
return
|
|
107
|
+
return Boolean(flamegraphData?.loading) || Boolean(topTableData?.loading);
|
|
108
108
|
}
|
|
109
109
|
return false;
|
|
110
110
|
}, [currentView, flamegraphData?.loading, topTableData?.loading]);
|
|
@@ -124,7 +124,7 @@ export const ProfileView = ({
|
|
|
124
124
|
);
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
-
const downloadPProf = async (e: React.MouseEvent<HTMLElement>) => {
|
|
127
|
+
const downloadPProf = async (e: React.MouseEvent<HTMLElement>): Promise<void> => {
|
|
128
128
|
e.preventDefault();
|
|
129
129
|
if (profileSource == null || queryClient == null) {
|
|
130
130
|
return;
|
|
@@ -141,15 +141,15 @@ export const ProfileView = ({
|
|
|
141
141
|
}
|
|
142
142
|
};
|
|
143
143
|
|
|
144
|
-
const resetIcicleGraph = () => setCurPath([]);
|
|
144
|
+
const resetIcicleGraph = (): void => setCurPath([]);
|
|
145
145
|
|
|
146
|
-
const setNewCurPath = (path: string[]) => {
|
|
146
|
+
const setNewCurPath = (path: string[]): void => {
|
|
147
147
|
if (!arrayEquals(curPath, path)) {
|
|
148
148
|
setCurPath(path);
|
|
149
149
|
}
|
|
150
150
|
};
|
|
151
151
|
|
|
152
|
-
const switchProfileView = (view: VisualizationType) => {
|
|
152
|
+
const switchProfileView = (view: VisualizationType): void => {
|
|
153
153
|
if (view == null) {
|
|
154
154
|
return;
|
|
155
155
|
}
|
|
@@ -176,7 +176,7 @@ export const ProfileView = ({
|
|
|
176
176
|
/>
|
|
177
177
|
) : null}
|
|
178
178
|
|
|
179
|
-
<Button color="neutral" onClick={downloadPProf}>
|
|
179
|
+
<Button color="neutral" onClick={void downloadPProf}>
|
|
180
180
|
Download pprof
|
|
181
181
|
</Button>
|
|
182
182
|
</div>
|
|
@@ -30,7 +30,7 @@ export const ProfileViewWithData = ({
|
|
|
30
30
|
queryClient,
|
|
31
31
|
profileSource,
|
|
32
32
|
navigateTo,
|
|
33
|
-
}: ProfileViewWithDataProps) => {
|
|
33
|
+
}: ProfileViewWithDataProps): JSX.Element => {
|
|
34
34
|
const profileVisState = useProfileVisState();
|
|
35
35
|
const {currentView} = profileVisState;
|
|
36
36
|
const {
|
|
@@ -38,7 +38,7 @@ export const ProfileViewWithData = ({
|
|
|
38
38
|
response: flamegraphResponse,
|
|
39
39
|
error: flamegraphError,
|
|
40
40
|
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.FLAMEGRAPH_UNSPECIFIED, {
|
|
41
|
-
skip: currentView
|
|
41
|
+
skip: currentView !== 'icicle' && currentView !== 'both',
|
|
42
42
|
});
|
|
43
43
|
|
|
44
44
|
const {
|
|
@@ -46,7 +46,7 @@ export const ProfileViewWithData = ({
|
|
|
46
46
|
response: topTableResponse,
|
|
47
47
|
error: topTableError,
|
|
48
48
|
} = useQuery(queryClient, profileSource, QueryRequest_ReportType.TOP, {
|
|
49
|
-
skip: currentView
|
|
49
|
+
skip: currentView !== 'table' && currentView !== 'both',
|
|
50
50
|
});
|
|
51
51
|
|
|
52
52
|
const sampleUnit = profileSource.ProfileType().sampleUnit;
|
package/src/TopTable.tsx
CHANGED
|
@@ -26,7 +26,7 @@ interface TopTableProps {
|
|
|
26
26
|
sampleUnit: string;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
const Arrow = ({direction}: {direction: string | undefined}) => {
|
|
29
|
+
const Arrow = ({direction}: {direction: string | undefined}): JSX.Element => {
|
|
30
30
|
return (
|
|
31
31
|
<svg
|
|
32
32
|
className={`${direction !== undefined ? 'fill-[#161616] dark:fill-[#ffffff]' : ''}`}
|
|
@@ -41,7 +41,22 @@ const Arrow = ({direction}: {direction: string | undefined}) => {
|
|
|
41
41
|
);
|
|
42
42
|
};
|
|
43
43
|
|
|
44
|
-
const useSortableData = (
|
|
44
|
+
const useSortableData = (
|
|
45
|
+
top?: Top,
|
|
46
|
+
config = {key: 'cumulative', direction: 'desc'}
|
|
47
|
+
): {
|
|
48
|
+
items:
|
|
49
|
+
| Array<{
|
|
50
|
+
diff: number;
|
|
51
|
+
cumulative: number;
|
|
52
|
+
flat: number;
|
|
53
|
+
name: string | undefined;
|
|
54
|
+
meta?: TopNodeMeta | undefined;
|
|
55
|
+
}>
|
|
56
|
+
| undefined;
|
|
57
|
+
requestSort: (key: string) => void;
|
|
58
|
+
sortConfig: {key: string; direction: string} | null;
|
|
59
|
+
} => {
|
|
45
60
|
const [sortConfig, setSortConfig] = React.useState<{key: string; direction: string} | null>(
|
|
46
61
|
config
|
|
47
62
|
);
|
|
@@ -57,7 +72,7 @@ const useSortableData = (top?: Top, config = {key: 'cumulative', direction: 'des
|
|
|
57
72
|
}));
|
|
58
73
|
|
|
59
74
|
const sortedItems = React.useMemo(() => {
|
|
60
|
-
if (
|
|
75
|
+
if (items.length === 0) return;
|
|
61
76
|
|
|
62
77
|
const sortableItems = [...items];
|
|
63
78
|
if (sortConfig !== null) {
|
|
@@ -74,7 +89,7 @@ const useSortableData = (top?: Top, config = {key: 'cumulative', direction: 'des
|
|
|
74
89
|
return sortableItems;
|
|
75
90
|
}, [items, sortConfig]);
|
|
76
91
|
|
|
77
|
-
const requestSort = key => {
|
|
92
|
+
const requestSort = (key: string): void => {
|
|
78
93
|
let direction = 'desc';
|
|
79
94
|
if (sortConfig != null && sortConfig.key === key && sortConfig.direction === 'desc') {
|
|
80
95
|
direction = 'asc';
|
|
@@ -89,7 +104,7 @@ export const RowLabel = (meta: TopNodeMeta | undefined): string => {
|
|
|
89
104
|
if (meta === undefined) return '<unknown>';
|
|
90
105
|
const mapping = `${
|
|
91
106
|
meta?.mapping?.file !== undefined && meta?.mapping?.file !== ''
|
|
92
|
-
? `[${getLastItem(meta.mapping.file)}]`
|
|
107
|
+
? `[${getLastItem(meta.mapping.file) ?? ''}]`
|
|
93
108
|
: ''
|
|
94
109
|
}`;
|
|
95
110
|
if (meta.function?.name !== undefined && meta.function?.name !== '')
|
|
@@ -112,14 +127,14 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
112
127
|
const total = top != null ? top.list.length : 0;
|
|
113
128
|
if (total === 0) return <>Profile has no samples</>;
|
|
114
129
|
|
|
115
|
-
const getClassNamesFor = name => {
|
|
130
|
+
const getClassNamesFor = (name: string): string | undefined => {
|
|
116
131
|
if (sortConfig == null) {
|
|
117
132
|
return;
|
|
118
133
|
}
|
|
119
134
|
return sortConfig.key === name ? sortConfig.direction : undefined;
|
|
120
135
|
};
|
|
121
136
|
|
|
122
|
-
const addPlusSign = (num: string) => {
|
|
137
|
+
const addPlusSign = (num: string): string => {
|
|
123
138
|
if (num.charAt(0) === '0' || num.charAt(0) === '-') {
|
|
124
139
|
return num;
|
|
125
140
|
}
|
|
@@ -138,7 +153,9 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
138
153
|
onClick={() => requestSort('name')}
|
|
139
154
|
>
|
|
140
155
|
Name
|
|
141
|
-
<span
|
|
156
|
+
<span
|
|
157
|
+
className={`inline-block align-middle ml-2 ${getClassNamesFor('name') ?? ''}`}
|
|
158
|
+
>
|
|
142
159
|
<Arrow direction={getClassNamesFor('name')} />
|
|
143
160
|
</span>
|
|
144
161
|
</th>
|
|
@@ -147,7 +164,9 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
147
164
|
onClick={() => requestSort('flat')}
|
|
148
165
|
>
|
|
149
166
|
Flat
|
|
150
|
-
<span
|
|
167
|
+
<span
|
|
168
|
+
className={`inline-block align-middle ml-2 ${getClassNamesFor('flat') ?? ''}`}
|
|
169
|
+
>
|
|
151
170
|
<Arrow direction={getClassNamesFor('flat')} />
|
|
152
171
|
</span>
|
|
153
172
|
</th>
|
|
@@ -157,7 +176,9 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
157
176
|
>
|
|
158
177
|
Cumulative
|
|
159
178
|
<span
|
|
160
|
-
className={`inline-block align-middle ml-2 ${
|
|
179
|
+
className={`inline-block align-middle ml-2 ${
|
|
180
|
+
getClassNamesFor('cumulative') ?? ''
|
|
181
|
+
}`}
|
|
161
182
|
>
|
|
162
183
|
<Arrow direction={getClassNamesFor('cumulative')} />
|
|
163
184
|
</span>
|
|
@@ -168,7 +189,9 @@ export const TopTable = ({data: top, sampleUnit}: TopTableProps): JSX.Element =>
|
|
|
168
189
|
onClick={() => requestSort('diff')}
|
|
169
190
|
>
|
|
170
191
|
Diff
|
|
171
|
-
<span
|
|
192
|
+
<span
|
|
193
|
+
className={`inline-block align-middle ml-2 ${getClassNamesFor('diff') ?? ''}`}
|
|
194
|
+
>
|
|
172
195
|
<Arrow direction={getClassNamesFor('diff')} />
|
|
173
196
|
</span>
|
|
174
197
|
</th>
|
|
@@ -25,7 +25,7 @@ const DiffLegendBar = ({
|
|
|
25
25
|
}: {
|
|
26
26
|
onMouseEnter: () => void;
|
|
27
27
|
onMouseLeave: () => void;
|
|
28
|
-
}) => {
|
|
28
|
+
}): JSX.Element => {
|
|
29
29
|
const isDarkMode = useAppSelector(selectDarkMode);
|
|
30
30
|
|
|
31
31
|
return (
|
|
@@ -54,20 +54,20 @@ const DiffLegendBar = ({
|
|
|
54
54
|
);
|
|
55
55
|
};
|
|
56
56
|
|
|
57
|
-
const DiffLegend = () => {
|
|
57
|
+
const DiffLegend = (): JSX.Element => {
|
|
58
58
|
const [showLegendTooltip, setShowLegendTooltip] = useState(false);
|
|
59
59
|
const [popperElement, setPopperElement] = useState<HTMLDivElement | null>(null);
|
|
60
60
|
const [referenceElement, setReferenceElement] = useState<HTMLDivElement | null>(null);
|
|
61
61
|
|
|
62
|
-
const {styles, attributes
|
|
62
|
+
const {styles, attributes} = usePopper(referenceElement, popperElement, {
|
|
63
63
|
placement: 'auto-start',
|
|
64
64
|
strategy: 'absolute',
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
const handleMouseEnter = () => {
|
|
67
|
+
const handleMouseEnter = (): void => {
|
|
68
68
|
setShowLegendTooltip(true);
|
|
69
69
|
};
|
|
70
|
-
const handleMouseLeave = () => {
|
|
70
|
+
const handleMouseLeave = (): void => {
|
|
71
71
|
setShowLegendTooltip(false);
|
|
72
72
|
};
|
|
73
73
|
|
|
@@ -24,10 +24,10 @@ interface Props {
|
|
|
24
24
|
|
|
25
25
|
let timeoutHandle: ReturnType<typeof setTimeout> | null = null;
|
|
26
26
|
|
|
27
|
-
const ResultBox = ({value, className = ''}: Props) => {
|
|
27
|
+
const ResultBox = ({value, className = ''}: Props): JSX.Element => {
|
|
28
28
|
const [isCopied, setIsCopied] = useState<boolean>(false);
|
|
29
29
|
|
|
30
|
-
const onCopy = () => {
|
|
30
|
+
const onCopy = (): void => {
|
|
31
31
|
setIsCopied(true);
|
|
32
32
|
(window.document?.activeElement as HTMLElement)?.blur();
|
|
33
33
|
if (timeoutHandle != null) {
|
|
@@ -34,16 +34,16 @@ const ProfileShareModal = ({
|
|
|
34
34
|
closeModal,
|
|
35
35
|
queryRequest,
|
|
36
36
|
queryClient,
|
|
37
|
-
}: ProfileShareModalProps) => {
|
|
37
|
+
}: ProfileShareModalProps): JSX.Element => {
|
|
38
38
|
const [isShared, setIsShared] = useState(false);
|
|
39
39
|
const [loading, setLoading] = useState<boolean>(false);
|
|
40
40
|
const [error, setError] = useState<string>('');
|
|
41
41
|
const [description, setDescription] = useState<string>('');
|
|
42
42
|
const [sharedLink, setSharedLink] = useState<string>('');
|
|
43
43
|
const metadata = useGrpcMetadata();
|
|
44
|
-
const isFormDataValid = () => true;
|
|
44
|
+
const isFormDataValid = (): boolean => true;
|
|
45
45
|
|
|
46
|
-
const handleSubmit: () => void = async () => {
|
|
46
|
+
const handleSubmit: () => Promise<void> = async () => {
|
|
47
47
|
try {
|
|
48
48
|
setLoading(true);
|
|
49
49
|
const {response} = await queryClient.shareProfile(
|
|
@@ -60,7 +60,7 @@ const ProfileShareModal = ({
|
|
|
60
60
|
}
|
|
61
61
|
};
|
|
62
62
|
|
|
63
|
-
const onClose = () => {
|
|
63
|
+
const onClose = (): void => {
|
|
64
64
|
setLoading(false);
|
|
65
65
|
setError('');
|
|
66
66
|
setDescription('');
|
|
@@ -89,7 +89,7 @@ const ProfileShareModal = ({
|
|
|
89
89
|
className="w-fit mt-4"
|
|
90
90
|
onClick={e => {
|
|
91
91
|
e.preventDefault();
|
|
92
|
-
handleSubmit();
|
|
92
|
+
void handleSubmit();
|
|
93
93
|
}}
|
|
94
94
|
disabled={loading || !isFormDataValid()}
|
|
95
95
|
type="submit"
|
|
@@ -113,7 +113,7 @@ const ProfileShareModal = ({
|
|
|
113
113
|
);
|
|
114
114
|
};
|
|
115
115
|
|
|
116
|
-
const ProfileShareButton = ({queryRequest, queryClient}: Props) => {
|
|
116
|
+
const ProfileShareButton = ({queryRequest, queryClient}: Props): JSX.Element => {
|
|
117
117
|
const [isOpen, setIsOpen] = useState<boolean>(false);
|
|
118
118
|
|
|
119
119
|
return (
|
package/src/useDelayedLoader.ts
CHANGED
|
@@ -17,11 +17,11 @@ interface DelayedLoaderOptions {
|
|
|
17
17
|
delay?: number;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
const useDelayedLoader = (isLoading = false, options?: DelayedLoaderOptions) => {
|
|
21
|
-
const {delay = 500} = options
|
|
20
|
+
const useDelayedLoader = (isLoading = false, options?: DelayedLoaderOptions): boolean => {
|
|
21
|
+
const {delay = 500} = options ?? {};
|
|
22
22
|
const [isLoaderVisible, setIsLoaderVisible] = useState<boolean>(false);
|
|
23
23
|
useEffect(() => {
|
|
24
|
-
let showLoaderTimeout
|
|
24
|
+
let showLoaderTimeout: ReturnType<typeof setTimeout>;
|
|
25
25
|
if (isLoading && !isLoaderVisible) {
|
|
26
26
|
// if the request takes longer than half a second, show the loading icon
|
|
27
27
|
showLoaderTimeout = setTimeout(() => {
|
|
@@ -31,7 +31,7 @@ const useDelayedLoader = (isLoading = false, options?: DelayedLoaderOptions) =>
|
|
|
31
31
|
setIsLoaderVisible(false);
|
|
32
32
|
}
|
|
33
33
|
return () => clearTimeout(showLoaderTimeout);
|
|
34
|
-
}, [isLoading]);
|
|
34
|
+
}, [isLoading, isLoaderVisible, delay]);
|
|
35
35
|
|
|
36
36
|
return isLoaderVisible;
|
|
37
37
|
};
|
package/src/useQuery.tsx
CHANGED
|
@@ -35,7 +35,7 @@ export const useQuery = (
|
|
|
35
35
|
reportType: QueryRequest_ReportType,
|
|
36
36
|
options?: UseQueryOptions
|
|
37
37
|
): IQueryResult => {
|
|
38
|
-
const {skip = false} = options
|
|
38
|
+
const {skip = false} = options ?? {};
|
|
39
39
|
const [result, setResult] = useState<IQueryResult>({
|
|
40
40
|
response: null,
|
|
41
41
|
error: null,
|
|
@@ -60,7 +60,7 @@ export const useQuery = (
|
|
|
60
60
|
call.response
|
|
61
61
|
.then(response => setResult({response, error: null, isLoading: false}))
|
|
62
62
|
.catch(error => setResult({error, response: null, isLoading: false}));
|
|
63
|
-
}, [client, profileSource, metadata, reportType]);
|
|
63
|
+
}, [skip, client, profileSource, metadata, reportType]);
|
|
64
64
|
|
|
65
65
|
return result;
|
|
66
66
|
};
|
package/src/utils.ts
CHANGED