Skip to content

Commit c9fbafb

Browse files
committed
Factor out hook for receiving messages from the extension
1 parent 5969c6f commit c9fbafb

File tree

8 files changed

+45
-117
lines changed

8 files changed

+45
-117
lines changed
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import { useEffect } from "react";
2+
3+
/**
4+
* Invokes the given callback when a message is received from the extension.
5+
*/
6+
export function useMessageFromExtension<T>(
7+
onEvent: (event: T) => void,
8+
onEventDependencies: unknown[],
9+
): void {
10+
useEffect(() => {
11+
const listener = (evt: MessageEvent) => {
12+
if (evt.origin === window.origin) {
13+
onEvent(evt.data as T);
14+
} else {
15+
// sanitize origin
16+
const origin = evt.origin.replace(/\n|\r/g, "");
17+
console.error(`Invalid event origin ${origin}`);
18+
}
19+
};
20+
window.addEventListener("message", listener);
21+
22+
return () => {
23+
window.removeEventListener("message", listener);
24+
};
25+
// eslint-disable-next-line react-hooks/exhaustive-deps
26+
}, onEventDependencies);
27+
}

extensions/ql-vscode/src/view/compare/Compare.tsx

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useState, useEffect, useRef } from "react";
1+
import { useState, useRef } from "react";
22
import { styled } from "styled-components";
33

44
import type {
@@ -16,6 +16,7 @@ import CompareTable from "./CompareTable";
1616

1717
import "../results/resultsView.css";
1818
import { assertNever } from "../../common/helpers-pure";
19+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
1920

2021
const Header = styled.div`
2122
display: flex;
@@ -50,10 +51,7 @@ export function Compare(_: Record<string, never>): React.JSX.Element {
5051
comparison?.result &&
5152
(comparison.result.to.length || comparison.result.from.length);
5253

53-
useEffect(() => {
54-
const listener = (evt: MessageEvent) => {
55-
if (evt.origin === window.origin) {
56-
const msg: ToCompareViewMessage = evt.data;
54+
useMessageFromExtension<ToCompareViewMessage>((msg) => {
5755
switch (msg.t) {
5856
case "setComparisonQueryInfo":
5957
setQueryInfo(msg);
@@ -148,17 +146,6 @@ export function Compare(_: Record<string, never>): React.JSX.Element {
148146
default:
149147
assertNever(msg);
150148
}
151-
} else {
152-
// sanitize origin
153-
const origin = evt.origin.replace(/\n|\r/g, "");
154-
console.error(`Invalid event origin ${origin}`);
155-
}
156-
};
157-
window.addEventListener("message", listener);
158-
159-
return () => {
160-
window.removeEventListener("message", listener);
161-
};
162149
}, []);
163150

164151
if (!queryInfo || !comparison) {

extensions/ql-vscode/src/view/data-flow-paths/DataFlowPathsView.tsx

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
22
import type { ToDataFlowPathsMessage } from "../../common/interface-types";
33
import type { DataFlowPaths as DataFlowPathsDomainModel } from "../../variant-analysis/shared/data-flow-paths";
44
import { DataFlowPaths } from "./DataFlowPaths";
5+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
56

67
export type DataFlowPathsViewProps = {
78
dataFlowPaths?: DataFlowPathsDomainModel;
@@ -14,28 +15,12 @@ export function DataFlowPathsView({
1415
DataFlowPathsDomainModel | undefined
1516
>(initialDataFlowPaths);
1617

17-
useEffect(() => {
18-
const listener = (evt: MessageEvent) => {
19-
if (evt.origin === window.origin) {
20-
const msg: ToDataFlowPathsMessage = evt.data;
21-
if (msg.t === "setDataFlowPaths") {
18+
useMessageFromExtension<ToDataFlowPathsMessage>((msg) => {
2219
setDataFlowPaths(msg.dataFlowPaths);
2320

2421
// Scroll to the top of the page when we're rendering
2522
// new data flow paths.
2623
window.scrollTo(0, 0);
27-
}
28-
} else {
29-
// sanitize origin
30-
const origin = evt.origin.replace(/\n|\r/g, "");
31-
console.error(`Invalid event origin ${origin}`);
32-
}
33-
};
34-
window.addEventListener("message", listener);
35-
36-
return () => {
37-
window.removeEventListener("message", listener);
38-
};
3924
}, []);
4025

4126
if (!dataFlowPaths) {

extensions/ql-vscode/src/view/method-modeling/MethodModelingView.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { NoMethodSelected } from "./NoMethodSelected";
1212
import type { MethodModelingPanelViewState } from "../../model-editor/shared/view-state";
1313
import { MethodAlreadyModeled } from "./MethodAlreadyModeled";
1414
import { defaultModelConfig } from "../../model-editor/languages";
15+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
1516

1617
type Props = {
1718
initialViewState?: MethodModelingPanelViewState;
@@ -36,10 +37,7 @@ export function MethodModelingView({
3637
[modeledMethods, isMethodModified],
3738
);
3839

39-
useEffect(() => {
40-
const listener = (evt: MessageEvent) => {
41-
if (evt.origin === window.origin) {
42-
const msg: ToMethodModelingMessage = evt.data;
40+
useMessageFromExtension<ToMethodModelingMessage>((msg) => {
4341
switch (msg.t) {
4442
case "setMethodModelingPanelViewState":
4543
setViewState(msg.viewState);
@@ -66,17 +64,6 @@ export function MethodModelingView({
6664
default:
6765
assertNever(msg);
6866
}
69-
} else {
70-
// sanitize origin
71-
const origin = evt.origin.replace(/\n|\r/g, "");
72-
console.error(`Invalid event origin ${origin}`);
73-
}
74-
};
75-
window.addEventListener("message", listener);
76-
77-
return () => {
78-
window.removeEventListener("message", listener);
79-
};
8067
}, []);
8168

8269
if (!inModelingMode || !viewState?.language) {

extensions/ql-vscode/src/view/model-alerts/ModelAlerts.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
} from "../../model-editor/shared/model-alerts-filter-sort";
1919
import type { ModelAlertsFilterSortState } from "../../model-editor/shared/model-alerts-filter-sort";
2020
import type { ModeledMethod } from "../../model-editor/modeled-method";
21+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
2122

2223
type Props = {
2324
initialViewState?: ModelAlertsViewState;
@@ -67,10 +68,7 @@ export function ModelAlerts({
6768
null,
6869
);
6970

70-
useEffect(() => {
71-
const listener = (evt: MessageEvent) => {
72-
if (evt.origin === window.origin) {
73-
const msg: ToModelAlertsMessage = evt.data;
71+
useMessageFromExtension<ToModelAlertsMessage>((msg) => {
7472
switch (msg.t) {
7573
case "setModelAlertsViewState": {
7674
setViewState(msg.viewState);
@@ -97,17 +95,6 @@ export function ModelAlerts({
9795
break;
9896
}
9997
}
100-
} else {
101-
// sanitize origin
102-
const origin = evt.origin.replace(/\n|\r/g, "");
103-
console.error(`Invalid event origin ${origin}`);
104-
}
105-
};
106-
window.addEventListener("message", listener);
107-
108-
return () => {
109-
window.removeEventListener("message", listener);
110-
};
11198
}, []);
11299

113100
const modelAlerts = useMemo(() => {

extensions/ql-vscode/src/view/model-editor/ModelEditor.tsx

Lines changed: 2 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import { INITIAL_HIDE_MODELED_METHODS_VALUE } from "../../model-editor/shared/hi
2121
import type { AccessPathSuggestionOptions } from "../../model-editor/suggestions";
2222
import type { ModelEvaluationRunState } from "../../model-editor/shared/model-evaluation-run-state";
2323
import { ModelEvaluation } from "./ModelEvaluation";
24+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
2425

2526
const LoadingContainer = styled.div`
2627
text-align: center;
@@ -129,10 +130,7 @@ export function ModelEditor({
129130
AccessPathSuggestionOptions | undefined
130131
>(undefined);
131132

132-
useEffect(() => {
133-
const listener = (evt: MessageEvent) => {
134-
if (evt.origin === window.origin) {
135-
const msg: ToModelEditorMessage = evt.data;
133+
useMessageFromExtension<ToModelEditorMessage>((msg) => {
136134
switch (msg.t) {
137135
case "setModelEditorViewState":
138136
setViewState(msg.viewState);
@@ -159,17 +157,6 @@ export function ModelEditor({
159157
default:
160158
assertNever(msg);
161159
}
162-
} else {
163-
// sanitize origin
164-
const origin = evt.origin.replace(/\n|\r/g, "");
165-
console.error(`Invalid event origin ${origin}`);
166-
}
167-
};
168-
window.addEventListener("message", listener);
169-
170-
return () => {
171-
window.removeEventListener("message", listener);
172-
};
173160
}, []);
174161

175162
useEffect(() => {

extensions/ql-vscode/src/view/results/ResultsApp.tsx

Lines changed: 4 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -16,11 +16,12 @@ import {
1616
DEFAULT_USER_SETTINGS,
1717
GRAPH_TABLE_NAME,
1818
} from "../../common/interface-types";
19+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
1920
import { ResultTables } from "./ResultTables";
2021
import { onNavigation } from "./navigation";
2122

2223
import "./resultsView.css";
23-
import { useCallback, useEffect, useState } from "react";
24+
import { useCallback, useState } from "react";
2425

2526
/**
2627
* ResultsApp.tsx
@@ -113,8 +114,8 @@ export function ResultsApp() {
113114
[],
114115
);
115116

116-
const handleMessage = useCallback(
117-
(msg: IntoResultsViewMsg): void => {
117+
useMessageFromExtension<IntoResultsViewMsg>(
118+
(msg) => {
118119
switch (msg.t) {
119120
case "setUserSettings":
120121
setUserSettings(msg.userSettings);
@@ -189,26 +190,6 @@ export function ResultsApp() {
189190
[updateStateWithNewResultsInfo],
190191
);
191192

192-
const vscodeMessageHandler = useCallback(
193-
(evt: MessageEvent) => {
194-
// sanitize origin
195-
const origin = evt.origin.replace(/\n|\r/g, "");
196-
if (evt.origin === window.origin) {
197-
handleMessage(evt.data as IntoResultsViewMsg);
198-
} else {
199-
console.error(`Invalid event origin ${origin}`);
200-
}
201-
},
202-
[handleMessage],
203-
);
204-
205-
useEffect(() => {
206-
window.addEventListener("message", vscodeMessageHandler);
207-
return () => {
208-
window.removeEventListener("message", vscodeMessageHandler);
209-
};
210-
}, [vscodeMessageHandler]);
211-
212193
const { displayedResults, nextResultsInfo, isExpectingResultsUpdate } = state;
213194
if (
214195
displayedResults.results !== null &&

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

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useCallback, useEffect, useState } from "react";
1+
import { useCallback, useState } from "react";
22

33
import type {
44
VariantAnalysis as VariantAnalysisDomainModel,
@@ -13,6 +13,7 @@ import type { ToVariantAnalysisMessage } from "../../common/interface-types";
1313
import { vscode } from "../vscode-api";
1414
import { defaultFilterSortState } from "../../variant-analysis/shared/variant-analysis-filter-sort";
1515
import { sendTelemetry, useTelemetryOnChange } from "../common/telemetry";
16+
import { useMessageFromExtension } from "../common/useMessageFromExtension";
1617

1718
export type VariantAnalysisProps = {
1819
variantAnalysis?: VariantAnalysisDomainModel;
@@ -77,10 +78,7 @@ export function VariantAnalysis({
7778
debounceTimeoutMillis: 1000,
7879
});
7980

80-
useEffect(() => {
81-
const listener = (evt: MessageEvent) => {
82-
if (evt.origin === window.origin) {
83-
const msg: ToVariantAnalysisMessage = evt.data;
81+
useMessageFromExtension<ToVariantAnalysisMessage>((msg) => {
8482
if (msg.t === "setVariantAnalysis") {
8583
setVariantAnalysis(msg.variantAnalysis);
8684
vscode.setState({
@@ -109,17 +107,6 @@ export function VariantAnalysis({
109107
];
110108
});
111109
}
112-
} else {
113-
// sanitize origin
114-
const origin = evt.origin.replace(/\n|\r/g, "");
115-
console.error(`Invalid event origin ${origin}`);
116-
}
117-
};
118-
window.addEventListener("message", listener);
119-
120-
return () => {
121-
window.removeEventListener("message", listener);
122-
};
123110
}, []);
124111

125112
const copyRepositoryList = useCallback(() => {

0 commit comments

Comments
 (0)