Merge remote queries webview outline into main (#1027)
This commit is contained in:
@@ -37,6 +37,6 @@ export function watchTypeScript() {
|
||||
|
||||
/** Copy CSS files for the results view into the output directory. */
|
||||
export function copyViewCss() {
|
||||
return gulp.src('src/view/*.css')
|
||||
return gulp.src('src/**/view/*.css')
|
||||
.pipe(gulp.dest('out'));
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ export const config: webpack.Configuration = {
|
||||
entry: {
|
||||
resultsView: './src/view/results.tsx',
|
||||
compareView: './src/compare/view/Compare.tsx',
|
||||
remoteQueriesView: './src/remote-queries/view/RemoteQueries.tsx',
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, '..', 'out'),
|
||||
|
||||
@@ -284,6 +284,10 @@
|
||||
"command": "codeQL.runRemoteQuery",
|
||||
"title": "CodeQL: Run Remote Query"
|
||||
},
|
||||
{
|
||||
"command": "codeQL.openRemoteQueriesView",
|
||||
"title": "CodeQL: Open Remote Queries View"
|
||||
},
|
||||
{
|
||||
"command": "codeQL.runQueries",
|
||||
"title": "CodeQL: Run Queries in Selected Files"
|
||||
@@ -746,6 +750,10 @@
|
||||
"command": "codeQL.runRemoteQuery",
|
||||
"when": "config.codeQL.canary && editorLangId == ql && resourceExtname == .ql"
|
||||
},
|
||||
{
|
||||
"command": "codeQL.openRemoteQueriesView",
|
||||
"when": "config.codeQL.canary"
|
||||
},
|
||||
{
|
||||
"command": "codeQL.runQueries",
|
||||
"when": "false"
|
||||
|
||||
@@ -74,7 +74,8 @@ import {
|
||||
import { CodeQlStatusBarHandler } from './status-bar';
|
||||
|
||||
import { Credentials } from './authentication';
|
||||
import { runRemoteQuery } from './run-remote-query';
|
||||
import { runRemoteQuery } from './remote-queries/run-remote-query';
|
||||
import { RemoteQueriesInterfaceManager } from './remote-queries/remote-queries-interface';
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
@@ -501,23 +502,23 @@ async function activateWithInstalledDistribution(
|
||||
selectedQuery: Uri
|
||||
): Promise<void> {
|
||||
// selectedQuery is unpopulated when executing through the command palette
|
||||
const pathToQhelp = selectedQuery ? selectedQuery.fsPath : window.activeTextEditor?.document.uri.fsPath;
|
||||
if(pathToQhelp) {
|
||||
const pathToQhelp = selectedQuery ? selectedQuery.fsPath : window.activeTextEditor?.document.uri.fsPath;
|
||||
if (pathToQhelp) {
|
||||
// Create temporary directory
|
||||
const relativePathToMd = path.basename(pathToQhelp, '.qhelp') + '.md';
|
||||
const absolutePathToMd = path.join(qhelpTmpDir.name, relativePathToMd);
|
||||
const uri = Uri.file(absolutePathToMd);
|
||||
try {
|
||||
await cliServer.generateQueryHelp(pathToQhelp , absolutePathToMd);
|
||||
await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd);
|
||||
await commands.executeCommand('markdown.showPreviewToSide', uri);
|
||||
} catch (err) {
|
||||
const errorMessage = err.message.includes('Generating qhelp in markdown') ? (
|
||||
const errorMessage = err.message.includes('Generating qhelp in markdown') ? (
|
||||
`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.`
|
||||
) : `Could not open a preview of the generated file (${absolutePathToMd}).`;
|
||||
void helpers.showAndLogErrorMessage(errorMessage, { fullMessage: `${errorMessage}\n${err}` });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
async function openReferencedFile(
|
||||
@@ -743,6 +744,14 @@ async function activateWithInstalledDistribution(
|
||||
}
|
||||
)
|
||||
);
|
||||
|
||||
void logger.log('Initializing remote queries panel interface.');
|
||||
const rmpm = new RemoteQueriesInterfaceManager(
|
||||
ctx,
|
||||
logger
|
||||
);
|
||||
ctx.subscriptions.push(rmpm);
|
||||
|
||||
// The "runRemoteQuery" command is internal-only.
|
||||
ctx.subscriptions.push(
|
||||
commandRunnerWithProgress('codeQL.runRemoteQuery', async (
|
||||
|
||||
@@ -364,3 +364,23 @@ export interface ParsedResultSets {
|
||||
resultSetNames: string[];
|
||||
resultSet: ResultSet;
|
||||
}
|
||||
|
||||
export type FromRemoteQueriesMessage =
|
||||
| RemoteQueryLoadedMessage
|
||||
| RemoteQueryErrorMessage;
|
||||
|
||||
export type ToRemoteQueriesMessage =
|
||||
| OpenRemoteQueriesViewMessage;
|
||||
|
||||
export interface RemoteQueryLoadedMessage {
|
||||
t: 'remoteQueryLoaded';
|
||||
}
|
||||
|
||||
export interface OpenRemoteQueriesViewMessage {
|
||||
t: 'openRemoteQueriesView';
|
||||
}
|
||||
|
||||
export interface RemoteQueryErrorMessage {
|
||||
t: 'remoteQueryError';
|
||||
error: string;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,134 @@
|
||||
import { DisposableObject } from '../pure/disposable-object';
|
||||
import {
|
||||
WebviewPanel,
|
||||
ExtensionContext,
|
||||
window as Window,
|
||||
ViewColumn,
|
||||
Uri,
|
||||
} from 'vscode';
|
||||
import * as path from 'path';
|
||||
|
||||
import { tmpDir } from '../run-queries';
|
||||
import {
|
||||
ToRemoteQueriesMessage,
|
||||
FromRemoteQueriesMessage,
|
||||
} from '../pure/interface-types';
|
||||
import { Logger } from '../logging';
|
||||
import { getHtmlForWebview } from '../interface-utils';
|
||||
import { assertNever } from '../pure/helpers-pure';
|
||||
import { commandRunner } from '../commandRunner';
|
||||
|
||||
|
||||
export class RemoteQueriesInterfaceManager extends DisposableObject {
|
||||
private panel: WebviewPanel | undefined;
|
||||
private panelLoaded = false;
|
||||
private panelLoadedCallBacks: (() => void)[] = [];
|
||||
|
||||
constructor(
|
||||
private ctx: ExtensionContext,
|
||||
private logger: Logger,
|
||||
) {
|
||||
super();
|
||||
commandRunner('codeQL.openRemoteQueriesView', () => this.handleOpenRemoteQueriesView());
|
||||
this.panelLoadedCallBacks.push(() => {
|
||||
void logger.log('Remote queries view loaded');
|
||||
});
|
||||
}
|
||||
|
||||
async showResults() {
|
||||
this.getPanel().reveal(undefined, true);
|
||||
|
||||
await this.waitForPanelLoaded();
|
||||
await this.postMessage({
|
||||
t: 'openRemoteQueriesView',
|
||||
});
|
||||
}
|
||||
|
||||
getPanel(): WebviewPanel {
|
||||
if (this.panel == undefined) {
|
||||
const { ctx } = this;
|
||||
const panel = (this.panel = Window.createWebviewPanel(
|
||||
'remoteQueriesView',
|
||||
'Remote Query Results',
|
||||
{ viewColumn: ViewColumn.Active, preserveFocus: true },
|
||||
{
|
||||
enableScripts: true,
|
||||
enableFindWidget: true,
|
||||
retainContextWhenHidden: true,
|
||||
localResourceRoots: [
|
||||
Uri.file(tmpDir.name),
|
||||
Uri.file(path.join(this.ctx.extensionPath, 'out')),
|
||||
],
|
||||
}
|
||||
));
|
||||
this.panel.onDidDispose(
|
||||
() => {
|
||||
this.panel = undefined;
|
||||
},
|
||||
null,
|
||||
ctx.subscriptions
|
||||
);
|
||||
|
||||
const scriptPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/remoteQueriesView.js')
|
||||
);
|
||||
|
||||
const stylesheetPathOnDisk = Uri.file(
|
||||
ctx.asAbsolutePath('out/remote-queries/view/remoteQueries.css')
|
||||
);
|
||||
|
||||
panel.webview.html = getHtmlForWebview(
|
||||
panel.webview,
|
||||
scriptPathOnDisk,
|
||||
stylesheetPathOnDisk
|
||||
);
|
||||
panel.webview.onDidReceiveMessage(
|
||||
async (e) => this.handleMsgFromView(e),
|
||||
undefined,
|
||||
ctx.subscriptions
|
||||
);
|
||||
}
|
||||
return this.panel;
|
||||
}
|
||||
|
||||
private waitForPanelLoaded(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
if (this.panelLoaded) {
|
||||
resolve();
|
||||
} else {
|
||||
this.panelLoadedCallBacks.push(resolve);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async handleMsgFromView(
|
||||
msg: FromRemoteQueriesMessage
|
||||
): Promise<void> {
|
||||
switch (msg.t) {
|
||||
case 'remoteQueryLoaded':
|
||||
this.panelLoaded = true;
|
||||
this.panelLoadedCallBacks.forEach((cb) => cb());
|
||||
this.panelLoadedCallBacks = [];
|
||||
break;
|
||||
case 'remoteQueryError':
|
||||
void this.logger.log(
|
||||
`Remote query error: ${msg.error}`
|
||||
);
|
||||
break;
|
||||
default:
|
||||
assertNever(msg);
|
||||
}
|
||||
}
|
||||
|
||||
private postMessage(msg: ToRemoteQueriesMessage): Thenable<boolean> {
|
||||
return this.getPanel().webview.postMessage(msg);
|
||||
}
|
||||
|
||||
async handleOpenRemoteQueriesView() {
|
||||
this.getPanel().reveal(undefined, true);
|
||||
|
||||
await this.waitForPanelLoaded();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,14 +3,16 @@ import * as path from 'path';
|
||||
import * as yaml from 'js-yaml';
|
||||
import * as fs from 'fs-extra';
|
||||
import * as tmp from 'tmp-promise';
|
||||
import { askForLanguage, findLanguage, getOnDiskWorkspaceFolders, showAndLogErrorMessage, showAndLogInformationMessage, showInformationMessageWithAction } from './helpers';
|
||||
import { Credentials } from './authentication';
|
||||
import * as cli from './cli';
|
||||
import { logger } from './logging';
|
||||
import { getRemoteControllerRepo, getRemoteRepositoryLists, setRemoteControllerRepo } from './config';
|
||||
import { tmpDir } from './run-queries';
|
||||
import { ProgressCallback, UserCancellationException } from './commandRunner';
|
||||
import { askForLanguage, findLanguage, getOnDiskWorkspaceFolders, showAndLogErrorMessage, showAndLogInformationMessage, showAndLogWarningMessage, showInformationMessageWithAction } from '../helpers';
|
||||
import { Credentials } from '../authentication';
|
||||
import * as cli from '../cli';
|
||||
import { logger } from '../logging';
|
||||
import { getRemoteControllerRepo, getRemoteRepositoryLists, setRemoteControllerRepo } from '../config';
|
||||
import { tmpDir } from '../run-queries';
|
||||
import { ProgressCallback, UserCancellationException } from '../commandRunner';
|
||||
import { OctokitResponse } from '@octokit/types/dist-types';
|
||||
import * as unzipper from 'unzipper';
|
||||
|
||||
interface Config {
|
||||
repositories: string[];
|
||||
ref?: string;
|
||||
@@ -347,7 +349,6 @@ async function runRemoteQueriesApiRequest(
|
||||
queryPackBase64: string,
|
||||
dryRun = false
|
||||
): Promise<void> {
|
||||
|
||||
if (dryRun) {
|
||||
void showAndLogInformationMessage('[DRY RUN] Would have sent request. See extension log for the payload.');
|
||||
void logger.log(JSON.stringify({ ref, language, repositories, owner, repo, queryPackBase64: queryPackBase64.substring(0, 100) + '... ' + queryPackBase64.length + ' bytes' }));
|
||||
@@ -369,8 +370,8 @@ async function runRemoteQueriesApiRequest(
|
||||
}
|
||||
}
|
||||
);
|
||||
void showAndLogInformationMessage(`Successfully scheduled runs. [Click here to see the progress](https://github.com/${owner}/${repo}/actions/runs/${response.data.workflow_run_id}).`);
|
||||
|
||||
const workflowRunId = response.data.workflow_run_id;
|
||||
void showAndLogInformationMessage(`Successfully scheduled runs. [Click here to see the progress](https://github.com/${owner}/${repo}/actions/runs/${workflowRunId}).`);
|
||||
} catch (error) {
|
||||
await attemptRerun(error, credentials, ref, language, repositories, owner, repo, queryPackBase64, dryRun);
|
||||
}
|
||||
@@ -440,3 +441,118 @@ async function ensureNameAndSuite(queryPackDir: string, packRelativePath: string
|
||||
}];
|
||||
await fs.writeFile(packPath, yaml.safeDump(qlpack));
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists the workflow run artifacts for the given workflow run ID.
|
||||
* @param credentials Credentials for authenticating to the GitHub API.
|
||||
* @param owner
|
||||
* @param repo
|
||||
* @param workflowRunId The ID of the workflow run to list artifacts for.
|
||||
* @returns An array of artifact details (including artifact name and ID).
|
||||
*/
|
||||
async function listWorkflowRunArtifacts(
|
||||
credentials: Credentials,
|
||||
owner: string,
|
||||
repo: string,
|
||||
workflowRunId: number
|
||||
) {
|
||||
const octokit = await credentials.getOctokit();
|
||||
const response = await octokit.rest.actions.listWorkflowRunArtifacts({
|
||||
owner,
|
||||
repo,
|
||||
run_id: workflowRunId,
|
||||
});
|
||||
|
||||
return response.data.artifacts;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param artifactName The artifact name, as a string.
|
||||
* @param artifacts An array of artifact details (from the "list workflow run artifacts" API response).
|
||||
* @returns The artifact ID corresponding to the given artifact name.
|
||||
*/
|
||||
function getArtifactIDfromName(artifactName: string, artifacts: Array<{ id: number, name: string }>): number | undefined {
|
||||
const artifact = artifacts.find(a => a.name === artifactName);
|
||||
return artifact?.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Downloads an artifact from a workflow run.
|
||||
* @param credentials Credentials for authenticating to the GitHub API.
|
||||
* @param owner
|
||||
* @param repo
|
||||
* @param artifactId The ID of the artifact to download.
|
||||
* @returns The path to the enclosing directory of the unzipped artifact.
|
||||
*/
|
||||
async function downloadArtifact(
|
||||
credentials: Credentials,
|
||||
owner: string,
|
||||
repo: string,
|
||||
artifactId: number
|
||||
): Promise<string> {
|
||||
const octokit = await credentials.getOctokit();
|
||||
const response = await octokit.rest.actions.downloadArtifact({
|
||||
owner,
|
||||
repo,
|
||||
artifact_id: artifactId,
|
||||
archive_format: 'zip',
|
||||
});
|
||||
const artifactPath = path.join(tmpDir.name, `${artifactId}`);
|
||||
void logger.log(`Downloading artifact to ${artifactPath}.zip`);
|
||||
await fs.writeFile(
|
||||
`${artifactPath}.zip`,
|
||||
Buffer.from(response.data as ArrayBuffer)
|
||||
);
|
||||
|
||||
void logger.log(`Extracting artifact to ${artifactPath}`);
|
||||
await (
|
||||
await unzipper.Open.file(`${artifactPath}.zip`)
|
||||
).extract({ path: artifactPath });
|
||||
return artifactPath;
|
||||
}
|
||||
|
||||
interface ResultIndexItem {
|
||||
nwo: string;
|
||||
id: string;
|
||||
results_count: number;
|
||||
bqrs_file_size: number;
|
||||
sarif_file_size?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the result index file for a given remote queries run.
|
||||
* @param credentials Credentials for authenticating to the GitHub API.
|
||||
* @param owner
|
||||
* @param repo
|
||||
* @param workflowRunId The ID of the workflow run to get the result index for.
|
||||
* @returns An object containing the result index.
|
||||
*/
|
||||
export async function getResultIndex(
|
||||
credentials: Credentials,
|
||||
owner: string,
|
||||
repo: string,
|
||||
workflowRunId: number
|
||||
): Promise<ResultIndexItem[]> {
|
||||
const artifactList = await listWorkflowRunArtifacts(credentials, owner, repo, workflowRunId);
|
||||
const artifactId = getArtifactIDfromName('result-index', artifactList);
|
||||
if (!artifactId) {
|
||||
void showAndLogWarningMessage(
|
||||
`Could not find a result index for the [specified workflow](https://github.com/${owner}/${repo}/actions/runs/${workflowRunId}).
|
||||
Please check whether the workflow run has successfully completed.`
|
||||
);
|
||||
return [];
|
||||
}
|
||||
const artifactPath = await downloadArtifact(credentials, owner, repo, artifactId);
|
||||
const indexFilePath = path.join(artifactPath, 'index.json');
|
||||
if (!(await fs.pathExists(indexFilePath))) {
|
||||
void showAndLogWarningMessage('Could not find an `index.json` file in the result artifact.');
|
||||
return [];
|
||||
}
|
||||
const resultIndex = await fs.readFile(path.join(artifactPath, 'index.json'), 'utf8');
|
||||
|
||||
try {
|
||||
return JSON.parse(resultIndex);
|
||||
} catch (error) {
|
||||
throw new Error(`Invalid result index file: ${error}`);
|
||||
}
|
||||
}
|
||||
13
extensions/ql-vscode/src/remote-queries/view/.eslintrc.js
Normal file
13
extensions/ql-vscode/src/remote-queries/view/.eslintrc.js
Normal file
@@ -0,0 +1,13 @@
|
||||
module.exports = {
|
||||
env: {
|
||||
browser: true
|
||||
},
|
||||
extends: [
|
||||
"plugin:react/recommended"
|
||||
],
|
||||
settings: {
|
||||
react: {
|
||||
version: 'detect'
|
||||
}
|
||||
}
|
||||
}
|
||||
113
extensions/ql-vscode/src/remote-queries/view/RemoteQueries.tsx
Normal file
113
extensions/ql-vscode/src/remote-queries/view/RemoteQueries.tsx
Normal file
@@ -0,0 +1,113 @@
|
||||
import * as React from 'react';
|
||||
import * as Rdom from 'react-dom';
|
||||
import * as octicons from '../../view/octicons';
|
||||
|
||||
import { vscode } from '../../view/vscode-api';
|
||||
|
||||
interface AnalysisResult {
|
||||
nwo: string,
|
||||
resultCount: number,
|
||||
downloadLink: string,
|
||||
fileSize: string,
|
||||
}
|
||||
|
||||
interface Props {
|
||||
queryTitle: string;
|
||||
queryFile: string;
|
||||
totalRepositoryCount: number;
|
||||
totalResultCount: number;
|
||||
executionTimestamp: string;
|
||||
executionDuration: string;
|
||||
downloadLink: string;
|
||||
results: AnalysisResult[]
|
||||
}
|
||||
|
||||
const AnalysisResult = (props: AnalysisResult) => (
|
||||
<span>
|
||||
<span className="vscode-codeql__analysis-item">{octicons.repo}</span>
|
||||
<span className="vscode-codeql__analysis-item">{props.nwo}</span>
|
||||
<span className="vscode-codeql__analysis-item vscode-codeql__badge-container">
|
||||
<span className="vscode-codeql__badge">{props.resultCount}</span>
|
||||
</span>
|
||||
<span className="vscode-codeql__analysis-item">
|
||||
<a
|
||||
className="vscode-codeql__download-link"
|
||||
href={props.downloadLink}>
|
||||
{octicons.download}{props.fileSize}
|
||||
</a>
|
||||
</span>
|
||||
</span>
|
||||
);
|
||||
|
||||
export function RemoteQueries(props: Props): JSX.Element {
|
||||
return <div className="vscode-codeql__remote-queries-view">
|
||||
<h1 className="vscode-codeql__query-title">{props.queryTitle}</h1>
|
||||
|
||||
<p className="vscode-codeql__paragraph">
|
||||
{props.totalResultCount} results in {props.totalRepositoryCount} repositories
|
||||
({props.executionDuration}), {props.executionTimestamp}
|
||||
</p>
|
||||
<p className="vscode-codeql__paragraph">
|
||||
<span className="vscode-codeql__query-file">{octicons.file} <span>{props.queryFile}</span></span>
|
||||
<span>{octicons.codeSquare} <span>query</span></span>
|
||||
</p>
|
||||
|
||||
<div className="vscode-codeql__query-summary-container">
|
||||
<h2 className="vscode-codeql__query-summary-title">Repositories with results ({props.totalRepositoryCount}):</h2>
|
||||
<a className="vscode-codeql__summary-download-link vscode-codeql__download-link" href={props.downloadLink}>
|
||||
{octicons.download}Download all
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<ul className="vscode-codeql__results-list">
|
||||
{props.results.map(result =>
|
||||
<li key={result.nwo} className="vscode-codeql__results-list-item">
|
||||
<AnalysisResult {...result} />
|
||||
</li>
|
||||
)}
|
||||
</ul>
|
||||
</div>;
|
||||
}
|
||||
|
||||
const formatDate = (d: Date): string => {
|
||||
const datePart = d.toLocaleDateString(undefined, { day: 'numeric', month: 'short' });
|
||||
const timePart = d.toLocaleTimeString(undefined, { hour: 'numeric', minute: 'numeric', hour12: true });
|
||||
return `${datePart} at ${timePart}`;
|
||||
};
|
||||
|
||||
const data: Props = {
|
||||
queryTitle: 'Empty block',
|
||||
queryFile: 'example.ql',
|
||||
totalRepositoryCount: 13,
|
||||
totalResultCount: 72,
|
||||
executionTimestamp: formatDate(new Date()),
|
||||
executionDuration: '0.6 seconds',
|
||||
downloadLink: 'www.example.com',
|
||||
results: [
|
||||
{
|
||||
nwo: 'github/foo',
|
||||
resultCount: 35,
|
||||
downloadLink: 'www.example.com',
|
||||
fileSize: '12.3mb'
|
||||
},
|
||||
{
|
||||
nwo: 'github/bar',
|
||||
resultCount: 9,
|
||||
downloadLink: 'www.example.com',
|
||||
fileSize: '10.1mb'
|
||||
},
|
||||
{
|
||||
nwo: 'github/baz',
|
||||
resultCount: 80,
|
||||
downloadLink: 'www.example.com',
|
||||
fileSize: '11.2mb'
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
Rdom.render(
|
||||
<RemoteQueries {...data} />,
|
||||
document.getElementById('root'),
|
||||
// Post a message to the extension when fully loaded.
|
||||
() => vscode.postMessage({ t: 'remoteQueryLoaded' })
|
||||
);
|
||||
@@ -0,0 +1,90 @@
|
||||
.vscode-codeql__remote-queries-view {
|
||||
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Helvetica, Arial,
|
||||
sans-serif, Apple Color Emoji, Segoe UI Emoji;
|
||||
}
|
||||
|
||||
.vscode-codeql__paragraph {
|
||||
margin: 0.5em 0 0.5em 0;
|
||||
}
|
||||
|
||||
.vscode-codeql__download-link {
|
||||
display: inline-block;
|
||||
font-size: x-small;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.vscode-codeql__download-link svg {
|
||||
fill: var(--vscode-textLink-foreground);
|
||||
}
|
||||
|
||||
.vscode-codeql__query-title {
|
||||
font-size: large;
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.octicon {
|
||||
fill: var(--vscode-editor-foreground);
|
||||
height: 1.2em;
|
||||
width: 1.2em;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.octicon-light {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.vscode-codeql__query-file {
|
||||
padding-right: 1em;
|
||||
}
|
||||
|
||||
.vscode-codeql__query-summary-container {
|
||||
padding-top: 1.5em;
|
||||
}
|
||||
|
||||
.vscode-codeql__query-summary-title {
|
||||
font-size: medium;
|
||||
font-weight: 500;
|
||||
padding: 0 0.5em 0 0;
|
||||
margin: 0;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.vscode-codeql__summary-download-link {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.vscode-codeql__results-list {
|
||||
list-style-type: none;
|
||||
margin: 0;
|
||||
padding: 0.5em 0 0 0;
|
||||
}
|
||||
|
||||
.vscode-codeql__results-list-item {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
.vscode-codeql__analysis-item {
|
||||
padding-right: 0.1em;
|
||||
}
|
||||
|
||||
.vscode-codeql__badge-container {
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
min-height: 100vh;
|
||||
padding-left: 0.2em;
|
||||
}
|
||||
|
||||
.vscode-codeql__badge {
|
||||
display: inline-block;
|
||||
min-width: 1.5em;
|
||||
padding: 0.3em;
|
||||
border-radius: 35%;
|
||||
font-size: x-small;
|
||||
text-align: center;
|
||||
background: var(--vscode-badge-background);
|
||||
color: var(--vscode-badge-foreground);
|
||||
border-color: var(--vscode-badge-background);
|
||||
}
|
||||
18
extensions/ql-vscode/src/remote-queries/view/tsconfig.json
Normal file
18
extensions/ql-vscode/src/remote-queries/view/tsconfig.json
Normal file
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"module": "esnext",
|
||||
"moduleResolution": "node",
|
||||
"target": "es6",
|
||||
"outDir": "out",
|
||||
"lib": ["es6", "dom"],
|
||||
"jsx": "react",
|
||||
"sourceMap": true,
|
||||
"rootDir": "..",
|
||||
"strict": true,
|
||||
"noUnusedLocals": true,
|
||||
"noImplicitReturns": true,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"experimentalDecorators": true
|
||||
},
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@@ -20,3 +20,23 @@ export const listUnordered = <svg className="octicon octicon-light" width="16" h
|
||||
export const info = <svg className="octicon octicon-light" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg" >
|
||||
<path fillRule="evenodd" clipRule="evenodd" d="M8.568 1.03a6.8 6.8 0 0 1 4.192 2.02 7.06 7.06 0 0 1 .46 9.39 6.85 6.85 0 0 1-8.58 1.74 7 7 0 0 1-3.12-3.5 7.12 7.12 0 0 1-.23-4.71 7 7 0 0 1 2.77-3.79 6.8 6.8 0 0 1 4.508-1.15zm.472 12.85a5.89 5.89 0 0 0 3.41-2.07 6.07 6.07 0 0 0-.4-8.06 5.82 5.82 0 0 0-7.43-.74 6.06 6.06 0 0 0 .5 10.29 5.81 5.81 0 0 0 3.92.58zM8.51 7h-1v4h1V7zm0-2h-1v1h1V5z" />
|
||||
</svg>;
|
||||
|
||||
/**
|
||||
* The icons below come from https://primer.style/octicons/
|
||||
*/
|
||||
|
||||
export const file = <svg className="octicon octicon-light" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" d="M3.75 1.5a.25.25 0 00-.25.25v11.5c0 .138.112.25.25.25h8.5a.25.25 0 00.25-.25V6H9.75A1.75 1.75 0 018 4.25V1.5H3.75zm5.75.56v2.19c0 .138.112.25.25.25h2.19L9.5 2.06zM2 1.75C2 .784 2.784 0 3.75 0h5.086c.464 0 .909.184 1.237.513l3.414 3.414c.329.328.513.773.513 1.237v8.086A1.75 1.75 0 0112.25 15h-8.5A1.75 1.75 0 012 13.25V1.75z"></path>
|
||||
</svg>;
|
||||
|
||||
export const codeSquare = <svg className="octicon octicon-light" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" d="M1.75 1.5a.25.25 0 00-.25.25v12.5c0 .138.112.25.25.25h12.5a.25.25 0 00.25-.25V1.75a.25.25 0 00-.25-.25H1.75zM0 1.75C0 .784.784 0 1.75 0h12.5C15.216 0 16 .784 16 1.75v12.5A1.75 1.75 0 0114.25 16H1.75A1.75 1.75 0 010 14.25V1.75zm9.22 3.72a.75.75 0 000 1.06L10.69 8 9.22 9.47a.75.75 0 101.06 1.06l2-2a.75.75 0 000-1.06l-2-2a.75.75 0 00-1.06 0zM6.78 6.53a.75.75 0 00-1.06-1.06l-2 2a.75.75 0 000 1.06l2 2a.75.75 0 101.06-1.06L5.31 8l1.47-1.47z"></path>
|
||||
</svg>;
|
||||
|
||||
export const repo = <svg className="octicon octicon-light" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" d="M2 2.5A2.5 2.5 0 014.5 0h8.75a.75.75 0 01.75.75v12.5a.75.75 0 01-.75.75h-2.5a.75.75 0 110-1.5h1.75v-2h-8a1 1 0 00-.714 1.7.75.75 0 01-1.072 1.05A2.495 2.495 0 012 11.5v-9zm10.5-1V9h-8c-.356 0-.694.074-1 .208V2.5a1 1 0 011-1h8zM5 12.25v3.25a.25.25 0 00.4.2l1.45-1.087a.25.25 0 01.3 0L8.6 15.7a.25.25 0 00.4-.2v-3.25a.25.25 0 00-.25-.25h-3.5a.25.25 0 00-.25.25z"></path>
|
||||
</svg>;
|
||||
|
||||
export const download = <svg className="octicon octicon-light" width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path fillRule="evenodd" d="M7.47 10.78a.75.75 0 001.06 0l3.75-3.75a.75.75 0 00-1.06-1.06L8.75 8.44V1.75a.75.75 0 00-1.5 0v6.69L4.78 5.97a.75.75 0 00-1.06 1.06l3.75 3.75zM3.75 13a.75.75 0 000 1.5h8.5a.75.75 0 000-1.5h-8.5z"></path>
|
||||
</svg>;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { FromCompareViewMessage, FromResultsViewMsg } from '../pure/interface-types';
|
||||
import { FromCompareViewMessage, FromRemoteQueriesMessage, FromResultsViewMsg } from '../pure/interface-types';
|
||||
|
||||
export interface VsCodeApi {
|
||||
/**
|
||||
* Post message back to vscode extension.
|
||||
*/
|
||||
postMessage(msg: FromResultsViewMsg | FromCompareViewMessage): void;
|
||||
postMessage(msg: FromResultsViewMsg | FromCompareViewMessage | FromRemoteQueriesMessage): void;
|
||||
}
|
||||
|
||||
declare const acquireVsCodeApi: () => VsCodeApi;
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as fs from 'fs-extra';
|
||||
import * as os from 'os';
|
||||
import * as yaml from 'js-yaml';
|
||||
|
||||
import { QlPack, runRemoteQuery } from '../../run-remote-query';
|
||||
import { QlPack, runRemoteQuery } from '../../remote-queries/run-remote-query';
|
||||
import { Credentials } from '../../authentication';
|
||||
import { CliVersionConstraint, CodeQLCliServer } from '../../cli';
|
||||
import { CodeQLExtensionInterface } from '../../extension';
|
||||
|
||||
Reference in New Issue
Block a user