Factor out hook for receiving messages from the extension
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
import { useEffect } from "react";
|
||||
|
||||
/**
|
||||
* Invokes the given callback when a message is received from the extension.
|
||||
*/
|
||||
export function useMessageFromExtension<T>(
|
||||
onEvent: (event: T) => void,
|
||||
onEventDependencies: unknown[],
|
||||
): void {
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
onEvent(evt.data as T);
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, onEventDependencies);
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useState, useEffect, useRef } from "react";
|
||||
import { useState, useRef } from "react";
|
||||
import { styled } from "styled-components";
|
||||
|
||||
import type {
|
||||
@@ -16,6 +16,7 @@ import CompareTable from "./CompareTable";
|
||||
|
||||
import "../results/resultsView.css";
|
||||
import { assertNever } from "../../common/helpers-pure";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
|
||||
const Header = styled.div`
|
||||
display: flex;
|
||||
@@ -50,10 +51,7 @@ export function Compare(_: Record<string, never>): React.JSX.Element {
|
||||
comparison?.result &&
|
||||
(comparison.result.to.length || comparison.result.from.length);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToCompareViewMessage = evt.data;
|
||||
useMessageFromExtension<ToCompareViewMessage>((msg) => {
|
||||
switch (msg.t) {
|
||||
case "setComparisonQueryInfo":
|
||||
setQueryInfo(msg);
|
||||
@@ -148,17 +146,6 @@ export function Compare(_: Record<string, never>): React.JSX.Element {
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!queryInfo || !comparison) {
|
||||
|
||||
@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
|
||||
import type { ToDataFlowPathsMessage } from "../../common/interface-types";
|
||||
import type { DataFlowPaths as DataFlowPathsDomainModel } from "../../variant-analysis/shared/data-flow-paths";
|
||||
import { DataFlowPaths } from "./DataFlowPaths";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
|
||||
export type DataFlowPathsViewProps = {
|
||||
dataFlowPaths?: DataFlowPathsDomainModel;
|
||||
@@ -14,28 +15,12 @@ export function DataFlowPathsView({
|
||||
DataFlowPathsDomainModel | undefined
|
||||
>(initialDataFlowPaths);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToDataFlowPathsMessage = evt.data;
|
||||
if (msg.t === "setDataFlowPaths") {
|
||||
useMessageFromExtension<ToDataFlowPathsMessage>((msg) => {
|
||||
setDataFlowPaths(msg.dataFlowPaths);
|
||||
|
||||
// Scroll to the top of the page when we're rendering
|
||||
// new data flow paths.
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!dataFlowPaths) {
|
||||
|
||||
@@ -12,6 +12,7 @@ import { NoMethodSelected } from "./NoMethodSelected";
|
||||
import type { MethodModelingPanelViewState } from "../../model-editor/shared/view-state";
|
||||
import { MethodAlreadyModeled } from "./MethodAlreadyModeled";
|
||||
import { defaultModelConfig } from "../../model-editor/languages";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
|
||||
type Props = {
|
||||
initialViewState?: MethodModelingPanelViewState;
|
||||
@@ -36,10 +37,7 @@ export function MethodModelingView({
|
||||
[modeledMethods, isMethodModified],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToMethodModelingMessage = evt.data;
|
||||
useMessageFromExtension<ToMethodModelingMessage>((msg) => {
|
||||
switch (msg.t) {
|
||||
case "setMethodModelingPanelViewState":
|
||||
setViewState(msg.viewState);
|
||||
@@ -66,17 +64,6 @@ export function MethodModelingView({
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (!inModelingMode || !viewState?.language) {
|
||||
|
||||
@@ -18,6 +18,7 @@ import {
|
||||
} from "../../model-editor/shared/model-alerts-filter-sort";
|
||||
import type { ModelAlertsFilterSortState } from "../../model-editor/shared/model-alerts-filter-sort";
|
||||
import type { ModeledMethod } from "../../model-editor/modeled-method";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
|
||||
type Props = {
|
||||
initialViewState?: ModelAlertsViewState;
|
||||
@@ -67,10 +68,7 @@ export function ModelAlerts({
|
||||
null,
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToModelAlertsMessage = evt.data;
|
||||
useMessageFromExtension<ToModelAlertsMessage>((msg) => {
|
||||
switch (msg.t) {
|
||||
case "setModelAlertsViewState": {
|
||||
setViewState(msg.viewState);
|
||||
@@ -97,17 +95,6 @@ export function ModelAlerts({
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const modelAlerts = useMemo(() => {
|
||||
|
||||
@@ -21,6 +21,7 @@ import { INITIAL_HIDE_MODELED_METHODS_VALUE } from "../../model-editor/shared/hi
|
||||
import type { AccessPathSuggestionOptions } from "../../model-editor/suggestions";
|
||||
import type { ModelEvaluationRunState } from "../../model-editor/shared/model-evaluation-run-state";
|
||||
import { ModelEvaluation } from "./ModelEvaluation";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
|
||||
const LoadingContainer = styled.div`
|
||||
text-align: center;
|
||||
@@ -129,10 +130,7 @@ export function ModelEditor({
|
||||
AccessPathSuggestionOptions | undefined
|
||||
>(undefined);
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToModelEditorMessage = evt.data;
|
||||
useMessageFromExtension<ToModelEditorMessage>((msg) => {
|
||||
switch (msg.t) {
|
||||
case "setModelEditorViewState":
|
||||
setViewState(msg.viewState);
|
||||
@@ -159,17 +157,6 @@ export function ModelEditor({
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
|
||||
@@ -16,11 +16,12 @@ import {
|
||||
DEFAULT_USER_SETTINGS,
|
||||
GRAPH_TABLE_NAME,
|
||||
} from "../../common/interface-types";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
import { ResultTables } from "./ResultTables";
|
||||
import { onNavigation } from "./navigation";
|
||||
|
||||
import "./resultsView.css";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
/**
|
||||
* ResultsApp.tsx
|
||||
@@ -113,8 +114,8 @@ export function ResultsApp() {
|
||||
[],
|
||||
);
|
||||
|
||||
const handleMessage = useCallback(
|
||||
(msg: IntoResultsViewMsg): void => {
|
||||
useMessageFromExtension<IntoResultsViewMsg>(
|
||||
(msg) => {
|
||||
switch (msg.t) {
|
||||
case "setUserSettings":
|
||||
setUserSettings(msg.userSettings);
|
||||
@@ -189,26 +190,6 @@ export function ResultsApp() {
|
||||
[updateStateWithNewResultsInfo],
|
||||
);
|
||||
|
||||
const vscodeMessageHandler = useCallback(
|
||||
(evt: MessageEvent) => {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
if (evt.origin === window.origin) {
|
||||
handleMessage(evt.data as IntoResultsViewMsg);
|
||||
} else {
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
},
|
||||
[handleMessage],
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener("message", vscodeMessageHandler);
|
||||
return () => {
|
||||
window.removeEventListener("message", vscodeMessageHandler);
|
||||
};
|
||||
}, [vscodeMessageHandler]);
|
||||
|
||||
const { displayedResults, nextResultsInfo, isExpectingResultsUpdate } = state;
|
||||
if (
|
||||
displayedResults.results !== null &&
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { useCallback, useState } from "react";
|
||||
|
||||
import type {
|
||||
VariantAnalysis as VariantAnalysisDomainModel,
|
||||
@@ -13,6 +13,7 @@ import type { ToVariantAnalysisMessage } from "../../common/interface-types";
|
||||
import { vscode } from "../vscode-api";
|
||||
import { defaultFilterSortState } from "../../variant-analysis/shared/variant-analysis-filter-sort";
|
||||
import { sendTelemetry, useTelemetryOnChange } from "../common/telemetry";
|
||||
import { useMessageFromExtension } from "../common/useMessageFromExtension";
|
||||
|
||||
export type VariantAnalysisProps = {
|
||||
variantAnalysis?: VariantAnalysisDomainModel;
|
||||
@@ -77,10 +78,7 @@ export function VariantAnalysis({
|
||||
debounceTimeoutMillis: 1000,
|
||||
});
|
||||
|
||||
useEffect(() => {
|
||||
const listener = (evt: MessageEvent) => {
|
||||
if (evt.origin === window.origin) {
|
||||
const msg: ToVariantAnalysisMessage = evt.data;
|
||||
useMessageFromExtension<ToVariantAnalysisMessage>((msg) => {
|
||||
if (msg.t === "setVariantAnalysis") {
|
||||
setVariantAnalysis(msg.variantAnalysis);
|
||||
vscode.setState({
|
||||
@@ -109,17 +107,6 @@ export function VariantAnalysis({
|
||||
];
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// sanitize origin
|
||||
const origin = evt.origin.replace(/\n|\r/g, "");
|
||||
console.error(`Invalid event origin ${origin}`);
|
||||
}
|
||||
};
|
||||
window.addEventListener("message", listener);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener("message", listener);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const copyRepositoryList = useCallback(() => {
|
||||
|
||||
Reference in New Issue
Block a user