Skip to content

Commit 7e64834

Browse files
authored
Merge remote queries webview outline into main (#1027)
1 parent 7495658 commit 7e64834

14 files changed

Lines changed: 562 additions & 20 deletions

File tree

extensions/ql-vscode/gulpfile.ts/typescript.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,6 @@ export function watchTypeScript() {
3737

3838
/** Copy CSS files for the results view into the output directory. */
3939
export function copyViewCss() {
40-
return gulp.src('src/view/*.css')
40+
return gulp.src('src/**/view/*.css')
4141
.pipe(gulp.dest('out'));
4242
}

extensions/ql-vscode/gulpfile.ts/webpack.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ export const config: webpack.Configuration = {
66
entry: {
77
resultsView: './src/view/results.tsx',
88
compareView: './src/compare/view/Compare.tsx',
9+
remoteQueriesView: './src/remote-queries/view/RemoteQueries.tsx',
910
},
1011
output: {
1112
path: path.resolve(__dirname, '..', 'out'),

extensions/ql-vscode/package.json

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,10 @@
284284
"command": "codeQL.runRemoteQuery",
285285
"title": "CodeQL: Run Remote Query"
286286
},
287+
{
288+
"command": "codeQL.openRemoteQueriesView",
289+
"title": "CodeQL: Open Remote Queries View"
290+
},
287291
{
288292
"command": "codeQL.runQueries",
289293
"title": "CodeQL: Run Queries in Selected Files"
@@ -746,6 +750,10 @@
746750
"command": "codeQL.runRemoteQuery",
747751
"when": "config.codeQL.canary && editorLangId == ql && resourceExtname == .ql"
748752
},
753+
{
754+
"command": "codeQL.openRemoteQueriesView",
755+
"when": "config.codeQL.canary"
756+
},
749757
{
750758
"command": "codeQL.runQueries",
751759
"when": "false"

extensions/ql-vscode/src/extension.ts

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,8 @@ import {
7474
import { CodeQlStatusBarHandler } from './status-bar';
7575

7676
import { Credentials } from './authentication';
77-
import { runRemoteQuery } from './run-remote-query';
77+
import { runRemoteQuery } from './remote-queries/run-remote-query';
78+
import { RemoteQueriesInterfaceManager } from './remote-queries/remote-queries-interface';
7879

7980
/**
8081
* extension.ts
@@ -501,23 +502,23 @@ async function activateWithInstalledDistribution(
501502
selectedQuery: Uri
502503
): Promise<void> {
503504
// selectedQuery is unpopulated when executing through the command palette
504-
const pathToQhelp = selectedQuery ? selectedQuery.fsPath : window.activeTextEditor?.document.uri.fsPath;
505-
if(pathToQhelp) {
505+
const pathToQhelp = selectedQuery ? selectedQuery.fsPath : window.activeTextEditor?.document.uri.fsPath;
506+
if (pathToQhelp) {
506507
// Create temporary directory
507508
const relativePathToMd = path.basename(pathToQhelp, '.qhelp') + '.md';
508509
const absolutePathToMd = path.join(qhelpTmpDir.name, relativePathToMd);
509510
const uri = Uri.file(absolutePathToMd);
510511
try {
511-
await cliServer.generateQueryHelp(pathToQhelp , absolutePathToMd);
512+
await cliServer.generateQueryHelp(pathToQhelp, absolutePathToMd);
512513
await commands.executeCommand('markdown.showPreviewToSide', uri);
513514
} catch (err) {
514-
const errorMessage = err.message.includes('Generating qhelp in markdown') ? (
515+
const errorMessage = err.message.includes('Generating qhelp in markdown') ? (
515516
`Could not generate markdown from ${pathToQhelp}: Bad formatting in .qhelp file.`
516517
) : `Could not open a preview of the generated file (${absolutePathToMd}).`;
517518
void helpers.showAndLogErrorMessage(errorMessage, { fullMessage: `${errorMessage}\n${err}` });
518519
}
519520
}
520-
521+
521522
}
522523

523524
async function openReferencedFile(
@@ -743,6 +744,14 @@ async function activateWithInstalledDistribution(
743744
}
744745
)
745746
);
747+
748+
void logger.log('Initializing remote queries panel interface.');
749+
const rmpm = new RemoteQueriesInterfaceManager(
750+
ctx,
751+
logger
752+
);
753+
ctx.subscriptions.push(rmpm);
754+
746755
// The "runRemoteQuery" command is internal-only.
747756
ctx.subscriptions.push(
748757
commandRunnerWithProgress('codeQL.runRemoteQuery', async (

extensions/ql-vscode/src/pure/interface-types.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,23 @@ export interface ParsedResultSets {
364364
resultSetNames: string[];
365365
resultSet: ResultSet;
366366
}
367+
368+
export type FromRemoteQueriesMessage =
369+
| RemoteQueryLoadedMessage
370+
| RemoteQueryErrorMessage;
371+
372+
export type ToRemoteQueriesMessage =
373+
| OpenRemoteQueriesViewMessage;
374+
375+
export interface RemoteQueryLoadedMessage {
376+
t: 'remoteQueryLoaded';
377+
}
378+
379+
export interface OpenRemoteQueriesViewMessage {
380+
t: 'openRemoteQueriesView';
381+
}
382+
383+
export interface RemoteQueryErrorMessage {
384+
t: 'remoteQueryError';
385+
error: string;
386+
}
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
import { DisposableObject } from '../pure/disposable-object';
2+
import {
3+
WebviewPanel,
4+
ExtensionContext,
5+
window as Window,
6+
ViewColumn,
7+
Uri,
8+
} from 'vscode';
9+
import * as path from 'path';
10+
11+
import { tmpDir } from '../run-queries';
12+
import {
13+
ToRemoteQueriesMessage,
14+
FromRemoteQueriesMessage,
15+
} from '../pure/interface-types';
16+
import { Logger } from '../logging';
17+
import { getHtmlForWebview } from '../interface-utils';
18+
import { assertNever } from '../pure/helpers-pure';
19+
import { commandRunner } from '../commandRunner';
20+
21+
22+
export class RemoteQueriesInterfaceManager extends DisposableObject {
23+
private panel: WebviewPanel | undefined;
24+
private panelLoaded = false;
25+
private panelLoadedCallBacks: (() => void)[] = [];
26+
27+
constructor(
28+
private ctx: ExtensionContext,
29+
private logger: Logger,
30+
) {
31+
super();
32+
commandRunner('codeQL.openRemoteQueriesView', () => this.handleOpenRemoteQueriesView());
33+
this.panelLoadedCallBacks.push(() => {
34+
void logger.log('Remote queries view loaded');
35+
});
36+
}
37+
38+
async showResults() {
39+
this.getPanel().reveal(undefined, true);
40+
41+
await this.waitForPanelLoaded();
42+
await this.postMessage({
43+
t: 'openRemoteQueriesView',
44+
});
45+
}
46+
47+
getPanel(): WebviewPanel {
48+
if (this.panel == undefined) {
49+
const { ctx } = this;
50+
const panel = (this.panel = Window.createWebviewPanel(
51+
'remoteQueriesView',
52+
'Remote Query Results',
53+
{ viewColumn: ViewColumn.Active, preserveFocus: true },
54+
{
55+
enableScripts: true,
56+
enableFindWidget: true,
57+
retainContextWhenHidden: true,
58+
localResourceRoots: [
59+
Uri.file(tmpDir.name),
60+
Uri.file(path.join(this.ctx.extensionPath, 'out')),
61+
],
62+
}
63+
));
64+
this.panel.onDidDispose(
65+
() => {
66+
this.panel = undefined;
67+
},
68+
null,
69+
ctx.subscriptions
70+
);
71+
72+
const scriptPathOnDisk = Uri.file(
73+
ctx.asAbsolutePath('out/remoteQueriesView.js')
74+
);
75+
76+
const stylesheetPathOnDisk = Uri.file(
77+
ctx.asAbsolutePath('out/remote-queries/view/remoteQueries.css')
78+
);
79+
80+
panel.webview.html = getHtmlForWebview(
81+
panel.webview,
82+
scriptPathOnDisk,
83+
stylesheetPathOnDisk
84+
);
85+
panel.webview.onDidReceiveMessage(
86+
async (e) => this.handleMsgFromView(e),
87+
undefined,
88+
ctx.subscriptions
89+
);
90+
}
91+
return this.panel;
92+
}
93+
94+
private waitForPanelLoaded(): Promise<void> {
95+
return new Promise((resolve) => {
96+
if (this.panelLoaded) {
97+
resolve();
98+
} else {
99+
this.panelLoadedCallBacks.push(resolve);
100+
}
101+
});
102+
}
103+
104+
private async handleMsgFromView(
105+
msg: FromRemoteQueriesMessage
106+
): Promise<void> {
107+
switch (msg.t) {
108+
case 'remoteQueryLoaded':
109+
this.panelLoaded = true;
110+
this.panelLoadedCallBacks.forEach((cb) => cb());
111+
this.panelLoadedCallBacks = [];
112+
break;
113+
case 'remoteQueryError':
114+
void this.logger.log(
115+
`Remote query error: ${msg.error}`
116+
);
117+
break;
118+
default:
119+
assertNever(msg);
120+
}
121+
}
122+
123+
private postMessage(msg: ToRemoteQueriesMessage): Thenable<boolean> {
124+
return this.getPanel().webview.postMessage(msg);
125+
}
126+
127+
async handleOpenRemoteQueriesView() {
128+
this.getPanel().reveal(undefined, true);
129+
130+
await this.waitForPanelLoaded();
131+
}
132+
133+
}
134+

0 commit comments

Comments
 (0)