Skip to content

Wire up data flow paths view #2182

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions extensions/ql-vscode/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

## [UNRELEASED]

- Show data flow paths of a variant analysis in a new tab

## 1.8.0 - 9 March 2023

- Send telemetry about unhandled errors happening within the extension. [#2125](https://github.com/github/vscode-codeql/pull/2125)
Expand Down
8 changes: 7 additions & 1 deletion extensions/ql-vscode/src/pure/interface-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,11 @@ export interface CancelVariantAnalysisMessage {
t: "cancelVariantAnalysis";
}

export interface ShowDataFlowPathsMessage {
t: "showDataFlowPaths";
dataFlowPaths: DataFlowPaths;
}

export type ToVariantAnalysisMessage =
| SetVariantAnalysisMessage
| SetRepoResultsMessage
Expand All @@ -462,7 +467,8 @@ export type FromVariantAnalysisMessage =
| CopyRepositoryListMessage
| ExportResultsMessage
| OpenLogsMessage
| CancelVariantAnalysisMessage;
| CancelVariantAnalysisMessage
| ShowDataFlowPathsMessage;

export interface SetDataFlowPathsMessage {
t: "setDataFlowPaths";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,14 @@
import * as React from "react";

import { ComponentStory, ComponentMeta } from "@storybook/react";
import { ThemeProvider } from "@primer/react";

import { CodePaths } from "../../view/common";
import type { CodeFlow } from "../../variant-analysis/shared/analysis-result";

export default {
title: "Code Paths",
component: CodePaths,
decorators: [
(Story) => (
<ThemeProvider colorMode="auto">
<Story />
</ThemeProvider>
),
],
decorators: [(Story) => <Story />],
} as ComponentMeta<typeof CodePaths>;

const Template: ComponentStory<typeof CodePaths> = (args) => (
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as React from "react";

import { ComponentMeta, ComponentStory } from "@storybook/react";

import { DataFlowPaths as DataFlowPathsComponent } from "../../view/data-flow-paths/DataFlowPaths";
import { createMockDataFlowPaths } from "../../../test/factories/variant-analysis/shared/data-flow-paths";
export default {
title: "Data Flow Paths/Data Flow Paths",
component: DataFlowPathsComponent,
} as ComponentMeta<typeof DataFlowPathsComponent>;

const Template: ComponentStory<typeof DataFlowPathsComponent> = (args) => (
<DataFlowPathsComponent {...args} />
);

export const PowerShell = Template.bind({});
PowerShell.args = {
dataFlowPaths: createMockDataFlowPaths(),
};
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,15 @@ import {
} from "../helpers";
import { telemetryListener } from "../telemetry";
import { redactableError } from "../pure/errors";
import { DataFlowPathsView } from "./data-flow-paths-view";
import { DataFlowPaths } from "./shared/data-flow-paths";

export class VariantAnalysisView
extends AbstractWebview<ToVariantAnalysisMessage, FromVariantAnalysisMessage>
implements VariantAnalysisViewInterface
{
public static readonly viewType = "codeQL.variantAnalysis";
private readonly dataFlowPathsView: DataFlowPathsView;

public constructor(
ctx: ExtensionContext,
Expand All @@ -36,6 +39,8 @@ export class VariantAnalysisView
super(ctx);

manager.registerView(this);

this.dataFlowPathsView = new DataFlowPathsView(ctx);
}

public async openView() {
Expand Down Expand Up @@ -154,6 +159,9 @@ export class VariantAnalysisView
this.variantAnalysisId,
);
break;
case "showDataFlowPaths":
await this.showDataFlows(msg.dataFlowPaths);
break;
case "telemetry":
telemetryListener?.sendUIInteraction(msg.action);
break;
Expand Down Expand Up @@ -204,4 +212,8 @@ export class VariantAnalysisView
? `${variantAnalysis.query.name} - Variant Analysis Results`
: `Variant Analysis ${this.variantAnalysisId} - Results`;
}

private async showDataFlows(dataFlows: DataFlowPaths): Promise<void> {
await this.dataFlowPathsView.showDataFlows(dataFlows);
}
}
49 changes: 13 additions & 36 deletions extensions/ql-vscode/src/view/common/CodePaths/CodePaths.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
import * as React from "react";
import { useRef, useState } from "react";
import styled from "styled-components";
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react";

import { Overlay, ThemeProvider } from "@primer/react";

import {
AnalysisMessage,
CodeFlow,
ResultSeverity,
} from "../../../variant-analysis/shared/analysis-result";
import { CodePathsOverlay } from "./CodePathsOverlay";
import { useTelemetryOnChange } from "../telemetry";
import { vscode } from "../../vscode-api";

const ShowPathsLink = styled(VSCodeLink)`
cursor: pointer;
Expand All @@ -24,46 +20,27 @@ export type CodePathsProps = {
severity: ResultSeverity;
};

const filterIsOpenTelemetry = (v: boolean) => v;

export const CodePaths = ({
codeFlows,
ruleDescription,
message,
severity,
}: CodePathsProps) => {
const [isOpen, setIsOpen] = useState(false);
useTelemetryOnChange(isOpen, "code-path-is-open", {
filterTelemetryOnValue: filterIsOpenTelemetry,
});

const linkRef = useRef<HTMLAnchorElement>(null);

const closeOverlay = () => setIsOpen(false);
const onShowPathsClick = () => {
vscode.postMessage({
t: "showDataFlowPaths",
dataFlowPaths: {
codeFlows,
ruleDescription,
message,
severity,
},
});
};

return (
<>
<ShowPathsLink onClick={() => setIsOpen(true)} ref={linkRef}>
Show paths
</ShowPathsLink>
{isOpen && (
<ThemeProvider colorMode="auto">
<Overlay
returnFocusRef={linkRef}
onEscape={closeOverlay}
onClickOutside={closeOverlay}
anchorSide="outside-top"
>
<CodePathsOverlay
codeFlows={codeFlows}
ruleDescription={ruleDescription}
message={message}
severity={severity}
onClose={closeOverlay}
/>
</Overlay>
</ThemeProvider>
)}
<ShowPathsLink onClick={onShowPathsClick}>Show paths</ShowPathsLink>
</>
);
};
112 changes: 0 additions & 112 deletions extensions/ql-vscode/src/view/common/CodePaths/CodePathsOverlay.tsx

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,25 @@ describe(CodePaths.name, () => {
/>,
);

it("renders correctly when unexpanded", () => {
it("renders 'show paths' link", () => {
render();

expect(screen.getByText("Show paths")).toBeInTheDocument();
expect(screen.queryByText("Code snippet text")).not.toBeInTheDocument();
expect(screen.queryByText("Rule description")).not.toBeInTheDocument();
});

it("renders correctly when expanded", async () => {
it("posts extension message when 'show paths' link clicked", async () => {
render();

await userEvent.click(screen.getByText("Show paths"));

expect(screen.getByText("Code snippet text")).toBeInTheDocument();
expect(screen.getByText("Rule description")).toBeInTheDocument();
expect((window as any).vsCodeApi.postMessage).toHaveBeenCalledWith({
t: "showDataFlowPaths",
dataFlowPaths: {
codeFlows: createMockCodeFlows(),
ruleDescription: "Rule description",
message: createMockAnalysisMessage(),
severity: "Recommendation",
},
});
});
});
Loading