diff --git a/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx b/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx new file mode 100644 index 00000000000..1631ae2ac97 --- /dev/null +++ b/extensions/ql-vscode/src/stories/compare/CompareTable.stories.tsx @@ -0,0 +1,70 @@ +import * as React from "react"; + +import { Meta, StoryFn } from "@storybook/react"; + +import CompareTableComponent from "../../view/compare/CompareTable"; + +import "../../view/results/resultsView.css"; + +export default { + title: "Compare/Compare Table", + component: CompareTableComponent, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const CompareTable = Template.bind({}); +CompareTable.args = { + comparison: { + t: "setComparisons", + stats: { + fromQuery: { + name: "Query built from user-controlled sources", + status: "finished in 0 seconds", + time: "8/16/2023, 3:08:37 PM", + }, + toQuery: { + name: "Query built from user-controlled sources", + status: "finished in 2 seconds", + time: "8/16/2023, 3:07:21 PM", + }, + }, + columns: [ + { name: "a", kind: "e" }, + { name: "b", kind: "e" }, + ], + commonResultSetNames: ["edges", "nodes", "subpaths", "#select"], + currentResultSetName: "edges", + rows: { + from: [], + to: [ + [ + { + label: "url : String", + url: { + uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java", + startLine: 22, + startColumn: 27, + endLine: 22, + endColumn: 57, + }, + }, + { + label: "url", + url: { + uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java", + startLine: 23, + startColumn: 33, + endLine: 23, + endColumn: 35, + }, + }, + ], + ], + }, + message: undefined, + databaseUri: "file:///java", + }, +}; diff --git a/extensions/ql-vscode/src/stories/results/ResultTablesHeader.stories.tsx b/extensions/ql-vscode/src/stories/results/ResultTablesHeader.stories.tsx new file mode 100644 index 00000000000..ccbadce07e9 --- /dev/null +++ b/extensions/ql-vscode/src/stories/results/ResultTablesHeader.stories.tsx @@ -0,0 +1,54 @@ +import * as React from "react"; + +import { Meta, StoryFn } from "@storybook/react"; + +import { ResultTablesHeader as ResultTablesHeaderComponent } from "../../view/results/ResultTablesHeader"; + +import "../../view/results/resultsView.css"; + +export default { + title: "Results/Result Tables Header", + component: ResultTablesHeaderComponent, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const ResultTablesHeader = Template.bind({}); +ResultTablesHeader.args = { + queryName: "test query", + queryPath: "/a/b/c/query.ql", + selectedTable: "#select", + parsedResultSets: { + pageNumber: 1, + pageSize: 10, + numPages: 2, + numInterpretedPages: 2, + resultSetNames: ["#select", "alerts"], + resultSet: { + t: "InterpretedResultSet", + schema: { + name: "#select", + rows: 15, + columns: [ + { + name: "x", + kind: "s", + }, + ], + }, + name: "#select", + interpretation: { + sourceLocationPrefix: "/home/bulk-builder/bulk-builder", + numTruncatedResults: 0, + numTotalResults: 15, + data: { + t: "SarifInterpretationData", + version: "2.1.0", + runs: [], + }, + }, + }, + }, +}; diff --git a/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx b/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx new file mode 100644 index 00000000000..a54723ee5c5 --- /dev/null +++ b/extensions/ql-vscode/src/stories/results/locations/ClickableLocation.stories.tsx @@ -0,0 +1,28 @@ +import * as React from "react"; + +import { Meta, StoryFn } from "@storybook/react"; + +import { ClickableLocation as ClickableLocationComponent } from "../../../view/results/locations/ClickableLocation"; + +import "../../../view/results/resultsView.css"; + +export default { + title: "Results/Clickable Location", + component: ClickableLocationComponent, +} as Meta; + +const Template: StoryFn = (args) => ( + +); + +export const ClickableLocation = Template.bind({}); +ClickableLocation.args = { + loc: { + uri: "file:/home/runner/work/sql2o-example/sql2o-example/src/main/java/org/example/HelloController.java", + startLine: 22, + startColumn: 27, + endLine: 22, + endColumn: 57, + }, + label: "url : String", +}; diff --git a/extensions/ql-vscode/src/view/common/TextButton.tsx b/extensions/ql-vscode/src/view/common/TextButton.tsx index 7760955c68d..321ad4d229a 100644 --- a/extensions/ql-vscode/src/view/common/TextButton.tsx +++ b/extensions/ql-vscode/src/view/common/TextButton.tsx @@ -15,13 +15,22 @@ const StyledButton = styled.button<{ size: Size }>` const TextButton = ({ size, onClick, + className, + title, children, }: { size?: Size; onClick: (e: React.MouseEvent) => void; + className?: string; + title?: string; children: React.ReactNode; }) => ( - + {children} ); diff --git a/extensions/ql-vscode/src/view/compare/CompareTable.tsx b/extensions/ql-vscode/src/view/compare/CompareTable.tsx index 4681671ef56..eabc7292943 100644 --- a/extensions/ql-vscode/src/view/compare/CompareTable.tsx +++ b/extensions/ql-vscode/src/view/compare/CompareTable.tsx @@ -7,11 +7,19 @@ import { ResultRow } from "../../common/bqrs-cli-types"; import RawTableRow from "../results/RawTableRow"; import { vscode } from "../vscode-api"; import { sendTelemetry } from "../common/telemetry"; +import TextButton from "../common/TextButton"; +import { styled } from "styled-components"; interface Props { comparison: SetComparisonsMessage; } +const OpenButton = styled(TextButton)` + cursor: pointer; + text-decoration: underline; + padding: 0; +`; + export default function CompareTable(props: Props) { const comparison = props.comparison; const rows = props.comparison.rows!; @@ -46,32 +54,14 @@ export default function CompareTable(props: Props) { - {/* - eslint-disable-next-line - jsx-a11y/anchor-is-valid, - jsx-a11y/click-events-have-key-events, - jsx-a11y/no-static-element-interactions - */} - openQuery("from")} - className="vscode-codeql__compare-open" - > + openQuery("from")}> {comparison.stats.fromQuery?.name} - + - {/* - eslint-disable-next-line - jsx-a11y/anchor-is-valid, - jsx-a11y/click-events-have-key-events, - jsx-a11y/no-static-element-interactions - */} - openQuery("to")} - className="vscode-codeql__compare-open" - > + openQuery("to")}> {comparison.stats.toQuery?.name} - + diff --git a/extensions/ql-vscode/src/view/results/AlertTable.tsx b/extensions/ql-vscode/src/view/results/AlertTable.tsx index f54d1735dfd..baacdb088cf 100644 --- a/extensions/ql-vscode/src/view/results/AlertTable.tsx +++ b/extensions/ql-vscode/src/view/results/AlertTable.tsx @@ -22,6 +22,7 @@ import { AlertTableHeader } from "./AlertTableHeader"; import { SarifMessageWithLocations } from "./locations/SarifMessageWithLocations"; import { SarifLocation } from "./locations/SarifLocation"; import { EmptyQueryResultsMessage } from "./EmptyQueryResultsMessage"; +import TextButton from "../common/TextButton"; import { AlertTableDropdownIndicatorCell } from "./AlertTableDropdownIndicatorCell"; type AlertTableProps = ResultTableProps & { @@ -74,13 +75,9 @@ export class AlertTable extends React.Component< return ( No Alerts. See{" "} - {/* - eslint-disable-next-line - jsx-a11y/anchor-is-valid, - */} - + raw results - + . ); diff --git a/extensions/ql-vscode/src/view/results/ResultTablesHeader.tsx b/extensions/ql-vscode/src/view/results/ResultTablesHeader.tsx index 69e5e465855..edaa1af4a92 100644 --- a/extensions/ql-vscode/src/view/results/ResultTablesHeader.tsx +++ b/extensions/ql-vscode/src/view/results/ResultTablesHeader.tsx @@ -8,6 +8,8 @@ import { ParsedResultSets, } from "../../common/interface-types"; import { basename } from "../../common/path"; +import { styled } from "styled-components"; +import TextButton from "../common/TextButton"; interface Props { queryName: string; @@ -16,6 +18,47 @@ interface Props { selectedTable: string; } +const Container = styled.span` + display: flex; + padding: 0.5em 0; + align-items: center; + top: 0; + background-color: var(--vscode-editorGutter-background); + position: sticky; + z-index: 1; +`; + +const PaginationButton = styled.button` + padding: 0.3rem; + margin: 0.2rem; + border: 0; + font-size: large; + color: var(--vscode-editor-foreground); + background-color: var(--vscode-editorGutter-background); + cursor: pointer; + opacity: 0.8; + + &:hover { + opacity: 1; + } +`; + +const PageNumberInput = styled.input` + border-radius: 0; + padding: 0.3rem; + margin: 0.2rem; + width: 2rem; + color: var(--vscode-editor-foreground); + border: 0; + border-bottom: 1px solid var(--vscode-editor-foreground); + background-color: var(--vscode-editorGutter-background); + outline: none; +`; + +const OpenQueryLink = styled(TextButton)` + text-decoration: none; +`; + export function ResultTablesHeader(props: Props) { const { queryPath, queryName, parsedResultSets, selectedTable } = props; @@ -104,9 +147,9 @@ export function ResultTablesHeader(props: Props) { }, [queryPath]); return ( - - - + « + / {numPages} - +
{queryName}
- {/* - eslint-disable-next-line - jsx-a11y/anchor-is-valid - */} - + Open {basename(queryPath)} - +
-
+ ); } diff --git a/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx b/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx index f94cbfe97ec..9301456af38 100644 --- a/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx +++ b/extensions/ql-vscode/src/view/results/locations/ClickableLocation.tsx @@ -2,6 +2,8 @@ import * as React from "react"; import { useCallback } from "react"; import { ResolvableLocationValue } from "../../../common/bqrs-cli-types"; import { jumpToLocation } from "../result-table-utils"; +import TextButton from "../../common/TextButton"; +import { styled } from "styled-components"; interface Props { loc: ResolvableLocationValue; @@ -11,6 +13,10 @@ interface Props { onClick?: () => void; } +const Link = styled(TextButton)` + text-decoration: none; +`; + /** * A clickable location link. */ @@ -31,20 +37,5 @@ export function ClickableLocation({ [loc, databaseUri, onClick], ); - return ( - <> - {/* - eslint-disable-next-line - jsx-a11y/anchor-is-valid, - */} - - {label} - - - ); + return {label}; } diff --git a/extensions/ql-vscode/src/view/results/resultsView.css b/extensions/ql-vscode/src/view/results/resultsView.css index 1208ea32251..ca296638521 100644 --- a/extensions/ql-vscode/src/view/results/resultsView.css +++ b/extensions/ql-vscode/src/view/results/resultsView.css @@ -11,16 +11,6 @@ justify-content: space-between; } -.vscode-codeql__table-selection-pagination { - display: flex; - padding: 0.5em 0; - align-items: center; - top: 0; - background-color: var(--vscode-editorGutter-background); - position: sticky; - z-index: 1; -} - .vscode-codeql__table-selection-header-item { padding-left: 2em; } @@ -29,35 +19,6 @@ border: 0; } -.vscode-codeql__table-selection-pagination button { - padding: 0.3rem; - margin: 0.2rem; - border: 0; - font-size: large; - color: var(--vscode-editor-foreground); - background-color: var(--vscode-editorGutter-background); - cursor: pointer; - opacity: 0.8; -} - -.vscode-codeql__table-selection-pagination button:hover { - opacity: 1; -} - -.vscode-codeql__table-selection-pagination input[type="number"] { - border-radius: 0; - padding: 0.3rem; - margin: 0.2rem; - width: 2rem; - border-radius: 0; - color: var(--vscode-editor-foreground); - border: 0; - border-bottom: 1px solid var(--vscode-editor-foreground); - background-color: var(--vscode-editorGutter-background); - border-radius: 0; - outline: none; -} - .vscode-codeql__result-table-alert-extras { display: inline-block; text-align: left; @@ -129,10 +90,6 @@ text-align: left; } -.vscode-codeql__result-table-location-link { - text-decoration: none; -} - select { background-color: var(--vscode-dropdown-background); color: var(--vscode-dropdown-foreground); @@ -228,11 +185,6 @@ td.vscode-codeql__path-index-cell { width: 100%; } -.vscode-codeql__compare-open { - cursor: pointer; - text-decoration: underline; -} - .vscode-codeql__compare-body > tbody { vertical-align: top; } @@ -249,3 +201,7 @@ td.vscode-codeql__path-index-cell { font-size: 14px; text-align: center; } + +.vscode-codeql__result-table-location-link { + text-decoration: none; +}