Skip to content

Commit 98a29d2

Browse files
Convert useStateWithTelemetry to useTelemetryOnChange
1 parent e9830ee commit 98a29d2

6 files changed

Lines changed: 61 additions & 81 deletions

File tree

extensions/ql-vscode/src/view/common/CodePaths/CodePaths.tsx

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import * as React from "react";
2-
import { useRef } from "react";
2+
import { useRef, useState } from "react";
33
import styled from "styled-components";
44
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react";
55

@@ -11,7 +11,7 @@ import {
1111
ResultSeverity,
1212
} from "../../../remote-queries/shared/analysis-result";
1313
import { CodePathsOverlay } from "./CodePathsOverlay";
14-
import { useStateWithTelemetry } from "../telemetry";
14+
import { useTelemetryOnChange } from "../telemetry";
1515

1616
const ShowPathsLink = styled(VSCodeLink)`
1717
cursor: pointer;
@@ -32,11 +32,10 @@ export const CodePaths = ({
3232
message,
3333
severity,
3434
}: CodePathsProps) => {
35-
const [isOpen, setIsOpen] = useStateWithTelemetry<boolean>(
36-
false,
37-
"code-path-is-open",
38-
filterIsOpenTelemetry,
39-
);
35+
const [isOpen, setIsOpen] = useState(false);
36+
useTelemetryOnChange(isOpen, "code-path-is-open", {
37+
filterTelemetryOnValue: filterIsOpenTelemetry,
38+
});
4039

4140
const linkRef = useRef<HTMLAnchorElement>(null);
4241

extensions/ql-vscode/src/view/common/CodePaths/CodePathsOverlay.tsx

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
11
import * as React from "react";
2+
import { useState } from "react";
23
import styled from "styled-components";
34

45
import {
56
AnalysisMessage,
67
CodeFlow,
78
ResultSeverity,
89
} from "../../../remote-queries/shared/analysis-result";
9-
import { useStateWithTelemetry } from "../telemetry";
10+
import { useTelemetryOnChange } from "../telemetry";
1011
import { SectionTitle } from "../SectionTitle";
1112
import { VerticalSpace } from "../VerticalSpace";
1213
import { CodeFlowsDropdown } from "./CodeFlowsDropdown";
@@ -76,10 +77,8 @@ export const CodePathsOverlay = ({
7677
severity,
7778
onClose,
7879
}: CodePathsOverlayProps) => {
79-
const [selectedCodeFlow, setSelectedCodeFlow] = useStateWithTelemetry(
80-
codeFlows[0],
81-
"code-flow-selected",
82-
);
80+
const [selectedCodeFlow, setSelectedCodeFlow] = useState(codeFlows[0]);
81+
useTelemetryOnChange(selectedCodeFlow, "code-flow-selected");
8382

8483
return (
8584
<OverlayContainer>

extensions/ql-vscode/src/view/common/telemetry.ts

Lines changed: 26 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,37 @@
1-
import * as React from "react";
2-
import { useState } from "react";
1+
import { useEffect, useRef } from "react";
32
import { vscode } from "../vscode-api";
43

54
/**
6-
* Wraps `React.useState` to output telemetry events whenever the value changes.
5+
* A react effect that outputs telemetry events whenever the value changes.
76
*
8-
* The only catch is that when using a predicate to filter which values output telemetry,
9-
* the setter only accepts a raw value, instead of a `(prevState: S) => S` function.
10-
*
11-
* @param defaultValue Default value to pass to React.useState
7+
* @param value Default value to pass to React.useState
128
* @param telemetryAction Name of the telemetry event to output
13-
* @param filterTelemetryOnValue If provided, only output telemetry events when the predicate returns true. If not provided always outputs telemetry.
14-
* @returns A value and a setter function, just as if from `React.useState`
9+
* @param options Extra optional arguments, including:
10+
* filterTelemetryOnValue: If provided, only output telemetry events when the
11+
* predicate returns true. If not provided always outputs telemetry.
1512
*/
16-
export function useStateWithTelemetry<S>(
17-
defaultValue: S | (() => S),
18-
telemetryAction: string,
19-
): [S, React.Dispatch<React.SetStateAction<S>>];
20-
export function useStateWithTelemetry<S>(
21-
defaultValue: S | (() => S),
13+
export function useTelemetryOnChange<S>(
14+
value: S,
2215
telemetryAction: string,
23-
filterTelemetryOnValue: (value: S) => boolean,
24-
): [S, React.Dispatch<S>];
25-
export function useStateWithTelemetry<S>(
26-
defaultValue: S | (() => S),
27-
telemetryAction: string,
28-
filterTelemetryOnValue?: (value: S) => boolean,
29-
): [S, React.Dispatch<S> | React.Dispatch<React.SetStateAction<S>>] {
30-
const [value, setter] = useState<S>(defaultValue);
31-
const setterWithTelemetry = React.useMemo<
32-
React.Dispatch<S> | React.Dispatch<React.SetStateAction<S>>
33-
>(() => {
34-
if (filterTelemetryOnValue === undefined) {
35-
return (x: React.SetStateAction<S>) => {
36-
sendTelemetry(telemetryAction);
37-
setter(x);
38-
};
39-
} else {
40-
return (x: S) => {
41-
if (filterTelemetryOnValue(x)) {
42-
sendTelemetry(telemetryAction);
43-
}
44-
setter(x);
45-
};
16+
options?: {
17+
filterTelemetryOnValue?: (value: S) => boolean;
18+
},
19+
) {
20+
const previousValue = useRef(value);
21+
const filterTelemetryOnValue = options?.filterTelemetryOnValue;
22+
23+
useEffect(() => {
24+
if (value === previousValue.current) {
25+
return;
4626
}
47-
}, [telemetryAction, filterTelemetryOnValue, setter]);
48-
return [value, setterWithTelemetry];
27+
previousValue.current = value;
28+
29+
if (filterTelemetryOnValue && !filterTelemetryOnValue(value)) {
30+
return;
31+
}
32+
33+
sendTelemetry(telemetryAction);
34+
}, [telemetryAction, filterTelemetryOnValue, value, previousValue]);
4935
}
5036

5137
export function sendTelemetry(telemetryAction: string) {

extensions/ql-vscode/src/view/remote-queries/RawResultsTable.tsx

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import * as React from "react";
2+
import { useState } from "react";
23
import styled from "styled-components";
34
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react";
45
import {
@@ -9,7 +10,7 @@ import {
910
import { tryGetRemoteLocation } from "../../pure/bqrs-utils";
1011
import TextButton from "./TextButton";
1112
import { convertNonPrintableChars } from "../../text-utils";
12-
import { sendTelemetry, useStateWithTelemetry } from "../common/telemetry";
13+
import { sendTelemetry, useTelemetryOnChange } from "../common/telemetry";
1314

1415
const numOfResultsInContractedMode = 5;
1516

@@ -108,11 +109,10 @@ const RawResultsTable = ({
108109
fileLinkPrefix,
109110
sourceLocationPrefix,
110111
}: RawResultsTableProps) => {
111-
const [tableExpanded, setTableExpanded] = useStateWithTelemetry<boolean>(
112-
false,
113-
"raw-results-table-expanded",
114-
filterTableExpandedTelemetry,
115-
);
112+
const [tableExpanded, setTableExpanded] = useState(false);
113+
useTelemetryOnChange(tableExpanded, "raw-results-table-expanded", {
114+
filterTelemetryOnValue: filterTableExpandedTelemetry,
115+
});
116116
const numOfResultsToShow = tableExpanded
117117
? results.rows.length
118118
: numOfResultsInContractedMode;

extensions/ql-vscode/src/view/variant-analysis/RepoRow.tsx

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { vscode } from "../vscode-api";
2424
import { AnalyzedRepoItemContent } from "./AnalyzedRepoItemContent";
2525
import StarCount from "../common/StarCount";
2626
import { LastUpdated } from "../common/LastUpdated";
27-
import { useStateWithTelemetry } from "../common/telemetry";
27+
import { useTelemetryOnChange } from "../common/telemetry";
2828

2929
// This will ensure that these icons have a className which we can use in the TitleContainer
3030
const ExpandCollapseCodicon = styled(Codicon)``;
@@ -170,11 +170,10 @@ export const RepoRow = ({
170170
selected,
171171
onSelectedChange,
172172
}: RepoRowProps) => {
173-
const [isExpanded, setExpanded] = useStateWithTelemetry<boolean>(
174-
false,
175-
"variant-analysis-repo-row-expanded",
176-
filterRepoRowExpandedTelemetry,
177-
);
173+
const [isExpanded, setExpanded] = useState(false);
174+
useTelemetryOnChange(isExpanded, "variant-analysis-repo-row-expanded", {
175+
filterTelemetryOnValue: filterRepoRowExpandedTelemetry,
176+
});
178177
const resultsLoaded = !!interpretedResults || !!rawResults;
179178
const [resultsLoading, setResultsLoading] = useState(false);
180179

@@ -189,7 +188,7 @@ export const RepoRow = ({
189188
downloadStatus !==
190189
VariantAnalysisScannedRepositoryDownloadStatus.Succeeded
191190
) {
192-
setExpanded(!isExpanded);
191+
setExpanded((oldIsExpanded) => !oldIsExpanded);
193192
return;
194193
}
195194

@@ -205,7 +204,6 @@ export const RepoRow = ({
205204
repository.fullName,
206205
status,
207206
downloadStatus,
208-
isExpanded,
209207
setExpanded,
210208
]);
211209

extensions/ql-vscode/src/view/variant-analysis/VariantAnalysis.tsx

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@ import { VariantAnalysisOutcomePanels } from "./VariantAnalysisOutcomePanels";
1212
import { VariantAnalysisLoading } from "./VariantAnalysisLoading";
1313
import { ToVariantAnalysisMessage } from "../../pure/interface-types";
1414
import { vscode } from "../vscode-api";
15-
import {
16-
defaultFilterSortState,
17-
RepositoriesFilterSortState,
18-
} from "../../pure/variant-analysis-filter-sort";
19-
import { useStateWithTelemetry } from "../common/telemetry";
15+
import { defaultFilterSortState } from "../../pure/variant-analysis-filter-sort";
16+
import { useTelemetryOnChange } from "../common/telemetry";
2017

2118
export type VariantAnalysisProps = {
2219
variantAnalysis?: VariantAnalysisDomainModel;
@@ -61,16 +58,17 @@ export function VariantAnalysis({
6158
const [repoResults, setRepoResults] =
6259
useState<VariantAnalysisScannedRepositoryResult[]>(initialRepoResults);
6360

64-
const [selectedRepositoryIds, setSelectedRepositoryIds] =
65-
useStateWithTelemetry<number[]>(
66-
[],
67-
"variant-analysis-selected-repository-ids",
68-
);
69-
const [filterSortState, setFilterSortState] =
70-
useStateWithTelemetry<RepositoriesFilterSortState>(
71-
defaultFilterSortState,
72-
"variant-analysis-filter-sort-state",
73-
);
61+
const [selectedRepositoryIds, setSelectedRepositoryIds] = useState<number[]>(
62+
[],
63+
);
64+
useTelemetryOnChange(
65+
selectedRepositoryIds,
66+
"variant-analysis-selected-repository-ids",
67+
);
68+
const [filterSortState, setFilterSortState] = useState(
69+
defaultFilterSortState,
70+
);
71+
useTelemetryOnChange(filterSortState, "variant-analysis-filter-sort-state");
7472

7573
useEffect(() => {
7674
const listener = (evt: MessageEvent) => {

0 commit comments

Comments
 (0)